多路IO复用——select函数

int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);     

参数1:监听的文件描述符的最大数+1

参数2:监听的读位图集合

参数3: 监听的写位图集合

参数4:监听的文件错误位图集合

参数5:设置一个监听时间,到了时间还没有发生监听事件就select返回0,否则返回监听到的文件描述符个数总和

参数2,3,4为传入传出参数,如果位图集合上相应位上的描述符被监听到,就会传出该位为1的位图集合。

明确要解决的问题,要实现多个客户端能随时与之进行交互的服务器,(即建立连接和数据交互),所以需要监听两个事件(对应两个文件描述符):1.有无新的客户端来与我进行连接,2.已连接的客户端与我有无数据交互。

我需要监听的文件描述符:lfd,cfd,下面为被监听函数:

1.accept(int lfd,struct sockaddr *addr,socklen_t *addrlen);

2. read(cfd, buffer ,n);

处理逻辑:只要我监听的文件描述符在读位图集合里就执行监听函数。

代码如下:

/**********************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include

#define PORT 8899

void sys_error(char *ptr){
    perror(ptr);
    exit(1);
}

int main(int argc,char* argv[]){
    int lfd=socket(AF_INET,SOCK_STREAM,0);
    if(lfd==-1){
        sys_error("sock error");
    }
    struct sockaddr_in server,client;
    server.sin_family=AF_INET;
    server.sin_port=htons(PORT);
    server.sin_addr.s_addr=htonl(0);

    int optval=-1;
    setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,(void*)&optval,sizeof(optval));
    
    int ret=bind(lfd,(struct sockaddr*)&server,sizeof(server));
    if(ret==-1){
        sys_error("bind error");
    }    
    ret=listen(lfd,64);
    //以上完成了服务器端套接字的初始化和绑定以及监听
    
    //select所需参数的定义以及初始化
    fd_set read_set,all_set;
    int nfds;
    FD_ZERO(&all_set);
    FD_SET(lfd,&all_set);
    nfds=lfd+1;

    socklen_t addrlen=sizeof(client);
    char buf[1024];
    while(1){
        read_set=all_set;
        int select_ret=select(nfds,&read_set,NULL,NULL,NULL);
        if(select_ret==-1){
            sys_error("select error");
        }
        if(FD_ISSET(lfd,&read_set)){
            int cfd=accept(lfd,(struct sockaddr*)&client,&addrlen);
            printf("新的客户端建立连接IP\n");
            FD_SET(cfd,&all_set);
            if(cfd>(nfds-1)){
                nfds=cfd+1;
            }
            if(--select==0){
                continue;
            }
        }
        for(int i=lfd+1;i<=nfds-1;i++){
            if(FD_ISSET(i,&read_set)){
                int read_ret=read(i,buf,sizeof(buf));
                if(read_ret==-1){
                    sys_error("read error");
                }
                else if(read_ret==0){
                    printf("断开连接\n");
                    close(i);
                    FD_CLR(i,&all_set);
                }
                else{
                    write(1,buf,read_ret);
                    write(i,buf,read_ret);
                }
                if(--select==0){
                    break;
                }
            }
        }        
    }
    return 0;
}




/***********************************************************/



你可能感兴趣的:(网络编程,套接字编程)