select函数的使用(网络编程)

使用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;
}

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值