【UNP学习_I/O复用之poll函数实现回射服务器】UNP学习_I/O复用之poll函数实现回射服务器
1、函数原型:
#includestruct pollfd{
int fd;
//文件描述符
short events;
//等待的事件
short revents;
//实际发生的事件
};
int poll(struct pollfd *fds,nfds_t nfds,int timeout);
//fds: 数组地址
//nfds: 数组的最大长度,数组中最后一个元素下标+1。内核会轮询fd数组中的每个文件描述符
//timeout: -1 : 永久阻塞;0 :调用完成立刻返回; >0等待的时长(ms)
//返回值:I/O发生变化的文件描述符的个数
2、实现代码
// File Name: poll_server.c
// Author: AlexanderGan
// Created Time: Wed 29 Jul 2020 04:31:41 PM CST#include
#include
#include
#include
#include
#include
#include
#include#include
#includeint main(int argc, char* argv[]){
if(argc < 2)
{
printf("eg: ./a.out IP port\n");
}
int port = atoi(argv[1]);
struct sockaddr_in serv_addr, client_addr;
socklen_t serv_len = sizeof(serv_addr);
socklen_t cli_len = sizeof(client_addr);
//创建套接字
int lfd = socket(AF_INET,SOCK_STREAM,0);
printf("lfd = %d\n",lfd);
//初始化服务器
memset(&serv_addr,0,serv_len);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(port);
//绑定ip和端口
bind(lfd,(struct sockaddr*)&serv_addr,serv_len);
//设置同时监听的最大个数
listen(lfd,36);
printf("Start accept !\n");
//poll结构体
struct pollfd allfd[1024];
int max_index = 0;
//初始化
for(int i = 0;
i < 1024;
i++){
allfd[i].fd = -1;
}
allfd[0].fd = lfd;
allfd[0].events = POLLIN;
while(1)
{
int i = 0;
int ret = poll(allfd,max_index+1,-1);
if(ret == -1)
{
printf("poll error!\n");
exit(1);
}if(allfd[0].revents & POLLIN){
int cfd = accept(lfd,(struct sockaddr*)&client_addr,&cli_len);
printf("======start======,cfd= %d\n",cfd);
//cfd添加到poll数组
for(i;
i < 1024;
++i){if(allfd[i].fd == -1)
{
printf("i = %d\n",i);
allfd[i].fd = cfd;
break;
}}
allfd[i].events = POLLIN;
//更新max_index
max_index = max_index < i ? i : max_index;
printf("max_index = %d\n",max_index);
}//遍历数组
for(i = 1;
i <= max_index;
i++){
int fd = allfd[i].fd;
printf("i = %d,fd = %d\n",i,fd);
if(fd == -1) continue;
bool res = (allfd[i].revents & POLLIN);
printf("res = %d\n",(int)res);
if(allfd[i].revents & POLLIN){
printf("recv!");
//接受数据
char buf[1024] = {0};
int len = recv(fd,buf,sizeof(buf),0);
printf("len == %d\n", len);
if(len == -1)
{
perror("recv error");
exit(1);
}
else if(len == 0)
{
allfd[i].fd = -1;
close(fd);
printf("客户端已主动断开连接。\n");
}
else
{
printf("recv buf = %s\n",buf);
//小写全变大写
for(int k = 0;
k < len;
++k)
{
buf[k] = toupper(buf[k]);
}
printf("buf toupper = %s\n",buf);
send(fd,buf,strlen(buf)+1,0);
}
}}
}
close(lfd);
return 0 ;
}
3、poll的优缺点
优点:
(1)可以等待多个描述符就绪。
(2)poll没有描述符数量的上限限制,因为在内核中它的遍历线性结构是基于链表来存储的。
缺点:
(1)每次调用poll,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大。
(2)同时每次调用poll都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大。
(3)poll不能跨平台,可移植性差。
(4)只支持水平触发。
推荐阅读
- linux网络编程|linux名称解析函数简介——gethostbyname与getaddrinfo
- guagga入门-我们对guagga的修改
- UNP学习_I/O复用之select函数实现回射服务器
- Linux网络编程|UNP学习_UDP广播服务器和客户端的实现
- Linux网络编程|UNP学习_组播服务器与客户端的实现
- Linux网络编程|UNP学习_I/0复用之epoll函数实现回射服务器