利用poll模型实现多个客户端和一个服务端的CS模型——多路IO复用技术
- poll函数
同select,委托内核监控可读可写事件
int poll(struct pollfd* fds, nfds_t nfds, int timeout);
param:
fds: 传入传出参数
fds.fd: 要监控的文件描述符,如果fd=-1,表示内核不再监控
fds.events: POLLIN-读事件
POLLOUT-写事件
fds.revents: 返回的事件,表示内核告诉程序有哪些文件描述符有事件发生
nfds: 告诉内核监控的范围,具体是fds数组下标的最大值+1
timeout: 超时时间
-1:永久阻塞
0:立刻返回
>0:阻塞时间
return:
>0: 表示发生文件描述符的个数
=0: 没有文件描述符发生变化
-1: 表示异常
注意
- struct pollfd结构体中的fd成员若被赋值成-1,是不会被内核监控的;
- 相较于select,poll没有本质上的变化,但是poll不受1024的限制;
- select可以跨平台使用,poll只能在linux上使用
服务端代码如下,客户端代码不变
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<netinet/in.h>
#include<errno.h>
#include<poll.h>
int main()
{
int lfd = socket(AF_INET, SOCK_STREAM, 0);
if(lfd < 0)
{
perror("socket error");
return -1;
}
struct sockaddr_in serv;
bzero(&serv, sizeof(serv));
serv.sin_family = AF_INET;
serv.sin_port = htons(8888);
serv.sin_addr.s_addr = htonl(INADDR_ANY);
int ret = bind(lfd, (struct sockaddr*)&serv, sizeof(serv));
if(ret < 0)
{
perror("bind error");
return -1;
}
listen(lfd, 128);
int i;
struct pollfd client[1024];
for(i=0; i<1024; i++)
{
client[i].fd = -1;
}
//将监听文件描述符委托内核监控
client[0].fd = lfd;
client[0].events = POLLIN;
int nready;
int max=0;//表示内核监控的范围,一开始有1个
int cfd;
int sockfd;
int n;
char buf[1024];
while(1)
{
nready = poll(client, max+1, -1);
if(nready < 0)
{
if(errno == EINTR)
continue;
perror("poll error\n");
exit(-1);
}
//有客户端连接请求到来
if((client[0].fd == lfd) && (client[0].revents & POLLIN))
{
cfd = accept(lfd, NULL, NULL);
//寻找client数组中的可用位置
for(i=1; i<1024; i++)
{
if(client[i].fd == -1)
{
client[i].fd = cfd;
client[i].events = POLLIN;
break;
}
}
//若没有可用位置,则关闭连接
if(i == 1024)
{
close(cfd);
continue;
}
max = i > max ? i : max;
//说明只有监听描述符被置为1,后面可跳过
if(--nready == 0)
{
continue;
}
}
//有数据发来
for(i=1; i<=max; i++)
{
//若fd=-1,表示连接已关闭或者没有连接
if(client[i].fd == -1)
{
continue;
}
if(client[i].revents == POLLIN)
{
sockfd = client[i].fd;
memset(buf, 0, sizeof(buf));
n = read(sockfd, buf, sizeof(buf));
if(n <= 0)
{
close(sockfd);
client[i].fd = -1;
printf("read error or client close\n");
}
printf("n == [%d], buf == [%s]\n", n, buf);
for(int j=0; j<n; j++)
{
buf[j] = toupper(buf[j]);
}
write(sockfd, buf, n);
}
}
}
close(lfd);
return 0;
}
【下一篇】:epoll模型