Linux--select

2024-11-03  本文已影响0人  锈色的栅栏

select函数概述

select允许程序可以监视多个文件描述符(套接字)的(可读,可写,异常),直到一个或多个文件描述符(套接字)准备就绪(超时),select解阻塞继续执行。

#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

select参数介绍

nfds: 是这三个集合中编号最高的文件描述符是加1。
readfds:监视readfds集合中的描述符是否读操作准备就绪。
writefds:监视writefds集合中的描述符是否写操作准备就绪
exceptfds:监视exceptfds集合中的描述符是否发生了异常。
timeout:超时时间,如果在超时时间内没有任意描述符准备好或异常,那么select超时时间一到也会解阻塞

struct timeval
{
    long tv_ sec; /* seconds */
    long tv_ usec; /* microseconds */
};

timeout有三种情况:
timeout为NULL 表示永远等待下去
timeout中所有成员问0, 不等待立即解阻塞
timeout中成员有固定的时间 表示等待该时间

返回值:
        > 0:表示就绪的文件描述符数量。
        =0:表示超时。
        -1:表示select出错。

描述符集合操作API

集合类型
       fd_set
清空集合
        void FD_ ZERO( fd_ set *fdset);
将fd描述符 添加到集合中
        void FD_ SET( int fd, fd_ set *fdset);
将fd描述符 从集合中删除
        void FD_CLR( int fd, fd_ set *fdset);
判断fd描述符 是否在集合中
        int FD_ ISSET( int fd, fd_ set *fdset);

示例代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/socket.h>//socket
#include <netinet/in.h> //struct sockaddr_in
#include <strings.h>
#include <sys/select.h>
#include <arpa/inet.h>

int create_tcp_socket(unsigned short port);
void sys_err(const char *err);

int main(int argc,char *argv[]) {   
        int lfd = create_tcp_socket(9999);       
        fd_set old_set,r_set;   
        FD_ZERO(&old_set);   
        FD_SET(lfd,&old_set);//将lfd添加到old_set中   
        int maxfd = lfd;   
        while (1)//select 需要循环监听文件描述符的状态   
        {       
                fd_set r_set = old_set;       
                int nready = select(maxfd+1,&r_set,NULL,NULL,NULL);       
                if(nready < 0){           
                        sys_err("select");       
                }else if(nready > 0){           
                        if(FD_ISSET(lfd,&r_set)){               
                                //printf("connect\n");               
                                struct sockaddr_in cil_addr;               
                                socklen_t cli_len = sizeof(cil_addr); 
                                int cfd = accept(lfd,(struct sockaddr *)&cil_addr,&cli_len); 
                               printf("connect %s : %hu\n",                                                inet_ntoa(cil_addr.sin_addr),ntohs(cil_addr.sin_port));
                                if(cfd > maxfd)                   
                                            maxfd = cfd;               
                                FD_SET(cfd,&old_set);               
                                if(--nready == 0)
                                            continue;           
                            }           
                             int i = 0;
                             for (i = lfd+1; i <= maxfd; i++)
                            {               
                                        if(FD_ISSET(i,&r_set)){
                                                unsigned char buf[1500] = "";
                                                int n = recv(i,buf,sizeof(buf),0);
                                                if(n < 0){ 
                                                           perror("recv");
                                                }else if (n == 0)
                                                { 
                                                           FD_CLR(i,&old_set);
                                                            close(i); 
                                                               printf("退出了\n");
                                                 }else if (n > 0)
                                                 { 
                                                           send(i,buf,n,0);
                                                 }
                                        }
                             }
               }   
        }   
     close(lfd);   
     return 0;
}

int create_tcp_socket(unsigned short port){   
        int lfd = socket(AF_INET,SOCK_STREAM,0);   
        if(lfd < 0)       
                sys_err("socket error");       
        int opt = 1;   
        setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));   
        struct sockaddr_in my_addr;   
        bzero(&my_addr,sizeof(my_addr));   
        my_addr.sin_family = AF_INET;   
        my_addr.sin_port = htons(port);   
        my_addr.sin_addr.s_addr = htonl(INADDR_ANY);   
        int ret = bind(lfd,(struct sockaddr *)&my_addr,sizeof(my_addr));   
        if(ret < 0)       
                sys_err("bind error");   
        listen(lfd,128);   
        return lfd;
}

void sys_err(const char *err){   
         perror(err);   
        _exit(-1);  
}

上一篇 下一篇

猜你喜欢

热点阅读