多路复用技术Linux下select模型代码实现
#include "wrap.h"
#include <sys/select.h>
#include <ctype.h>
#include <fcntl.h>
int main()
{
int lfd; //监听文件描述符
int cfd; //通信文件描述符
int nready; //select返回值(可读事件个数)
int maxfd; //最大监控范围
int n; //读取到的字节数
int i; //for循环变量
int sockfd; //赋值为通信文件描述符,方便操作
int flags; //用于更改通信文件描述符为非阻塞的中间变量
char buf[1024]; //存放读取到的数据
fd_set readfds, tempfds; //委托内核监控事件结构体(内部使用位操作)
//创建SOCKET、设置端口复用、绑定端口、监听
lfd = tcp4BindListen(9791, NULL, 128);
maxfd = lfd;
//初始化委托读事件结构体,并将监听文件描述符添加到结构体中
FD_ZERO(&readfds);
FD_SET(lfd, &readfds);
while(1)
{
tempfds = readfds;
nready = select(maxfd + 1, &tempfds, NULL, NULL, NULL);
if(nready < 0)
{
if(errno == EINTR)//被信号中断
{
continue;
}
break;
}
//有客户端请求连接
if(FD_ISSET(lfd, &tempfds))
{
cfd = Accept(lfd, NULL, NULL);
//设置通信文件描述符为非阻塞
flags = fcntl(cfd, F_GETFL, 0);
flags = flags | O_NONBLOCK;
fcntl(cfd, F_SETFL, flags);
//将通信文件描述符加入到读事件结构体中
FD_SET(cfd, &readfds);
//如果文件描述符比原有文件描述符的值都大,监控范围+1
if(maxfd < cfd)
{
maxfd = cfd;
}
//如果读事件-1后为0,跳出当前循环
if(--nready == 0)
{
continue;
}
}
//有客户端发送数据
for(i = lfd + 1; i <= maxfd; i++)
{
sockfd = i;
//如果sockfd有可读事件
if(FD_ISSET(sockfd, &tempfds))
{
while(1)
{
bzero(buf, sizeof(buf));
n = Read(sockfd, buf, sizeof(buf));
//如果客户断开连接
if(n == 0)
{
printf("客户断开连接\n");
close(sockfd);
FD_CLR(sockfd, &readfds);
break;
}
//如果数据读取完毕
else if(n < 0)
{
printf("数据接受完毕\n");
break;
}
//如果还有可读数据
else
{
printf("读取数据 %s", buf);
/*
核心操作
*/
}
}
//如果可读事件-1为0,跳出for循环
if(--nready == 0)
{
break;
}
}
}
}
//关闭监听文件描述符
close(lfd);
return 0;
}