使用select函数,
服务器不需要再去监听文件描述符,交给select去做,不需要再去阻塞等待事件的发生,一旦执行就会有返回值,根据返回值的情况可以判断该文件描述符是读事件,写事件还是异常事件。
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
nfds:最大的文件描述符+1
readfds:监听的读
writefds:监听的写
exceptfd:异常监听处理
timeout :是否超时
&成功返回满足条件的总数
void FD_ZERO(fd_set *set);//将set清空
void FD_CLR(int fd, fd_set *set);//将fd从set清除出去
int FD_ISSET(int fd, fd_set *set);//判断fd是否在set集合中
void FD_SET(int fd, fd_set *set);//将fd设置到set中去
示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <ctype.h>
int main()
{
int clifd[1024];//客户端最大链接数
int maxfd,lfd,confd,sockfd;
char buf[128],str[16];
int i,j,n;
struct sockaddr_in clie_addr,serv_addr;
socklen_t clie_len;
//allset暂时保存原来的状态
fd_set rset,allset;
lfd = socket(AF_INET,SOCK_STREAM,0);
//端口复用
int opt =1;
setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
bzero(&serv_addr,sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(8888);
serv_addr.sin_addr.s_addr = inet_addr("192.168.3.163");
bind(lfd,(struct sockaddr*)&serv_addr,sizeof(struct sockaddr));
listen(lfd,128);
maxfd = lfd;//lfd开始为最大文件描述符3
int maxi = -1;//用于client[]的下标,初始值指向0个元素之前下标位置
for(i=0;i<1024;i++)
clifd[i]=-1;//初始化全为-1
FD_ZERO(&allset);
FD_SET(lfd,&allset);//lfd加载到allset中
int ret;
while(1)
{
//每次循环都从新设置select监控信号集
rset = allset;
ret = select(maxfd+1,&rset,NULL,NULL,NULL);
if(ret<0)
perror("select error");
//判断lfd是否在读事件集合里
if(FD_ISSET(lfd,&rset)){
clie_len = sizeof(clie_addr);
confd = accept(lfd,(struct sockaddr*)&clie_addr,&clie_len);//4confd
printf("received from %s at PORT %d\n",
inet_ntop(AF_INET, &clie_addr.sin_addr, str, sizeof(str)),
ntohs(clie_addr.sin_port));
for(i=0;i<1024;i++)
{
if(clifd[i]<0)
{
clifd[i] = confd;
break;
}
if(i == 1024){
fputs("too many clients\n",stderr);
exit(1);
}
FD_SET(confd,&allset);
if(confd>maxfd)
maxfd = confd;
if(i>maxi)
maxi = i;
if(--ret ==0)
continue;
}
for(i=0;i<=maxi;i++)
{
if((sockfd = clifd[i])<0)continue;
if(FD_ISSET(sockfd,&rset)){
//当client关闭连接时,服务器也关闭对应的链接
if((n = read(sockfd,buf,sizeof(buf))==0)){
close(sockfd);
FD_CLR(sockfd,&allset);
clifd[i] = -1;
}
else if(n>0)
{
for (j = 0; j < n; j++)
buf[j] = toupper(buf[j]);
write(sockfd,buf,n);
write(STDOUT_FILENO,buf,n);
}
if(--ret==0)
{break;
}
}
}
}
}
close(lfd);
return 0;
}