select

来源:互联网 发布:python 解压war文件 编辑:程序博客网 时间:2024/06/05 20:41

套接字模式:阻塞套接字和非阻塞套接字。或者叫同步套接字和异步套接字。
套接字模型:描述如何对套接字的I/O行为进行管理。

一、 select模型的产生

先看一下下面的这句代码:
int iResult = recv(s, buffer,1024);
这是用来接收数据的,在默认的阻塞模式下的套接字里,recv会阻塞在那里,直到套接字连接上有数据可读,把数据读到buffer里后recv函数才会返回,不然就会一直阻塞在那里。在单线程的程序里出现这种情况会导致主线程(单线程程序里只有一个默认的主线程)被阻塞,这样整个程序被锁死在这里,如果永远没数据发送过来,那么程序就会被永远锁死。这个问题可以用多线程解决,但是在有多个套接字连接的情况下,这不是一个好的选择,扩展性很差。Select模型就是为了解决这个问题而出现的。

二、select模型简介

select返回fd_set中可用的套接字个数。 

fd_set是一个SOCKET队列,以下宏可以对该队列进行操作:

FD_CLR( s, *set) 从队列set删除句柄s;

FD_ISSET( s, *set) 检查句柄s是否存在与队列set中;

FD_SET( s, *set )把句柄s添加到队列set中;

FD_ZERO( *set ) 把set队列初始化成空队列.


三、LINUX 程序设计 select实例


/*  For our final example, server5.c,     we include the sys/time.h and sys/ioctl.h headers in place of signal.h    in our last program and declare some extra variables to deal with select.  */#include <sys/types.h>#include <sys/socket.h>#include <stdio.h>#include <netinet/in.h>#include <sys/time.h>#include <sys/ioctl.h>#include <unistd.h>#include <stdlib.h>int main(){    int server_sockfd, client_sockfd;    int server_len, client_len;    struct sockaddr_in server_address;    struct sockaddr_in client_address;    int result;    fd_set readfds, testfds;/*  Create and name a socket for the server.  */    server_sockfd = socket(AF_INET, SOCK_STREAM, 0);    server_address.sin_family = AF_INET;    server_address.sin_addr.s_addr = htonl(INADDR_ANY);    server_address.sin_port = htons(9734);    server_len = sizeof(server_address);    bind(server_sockfd, (struct sockaddr *)&server_address, server_len);/*  Create a connection queue and initialize readfds to handle input from server_sockfd.  */    listen(server_sockfd, 5);    FD_ZERO(&readfds);    FD_SET(server_sockfd, &readfds);/*  Now wait for clients and requests.    Since we have passed a null pointer as the timeout parameter, no timeout will occur.    The program will exit and report an error if select returns a value of less than 1.  */    while(1) {        char ch;         int fd;         int nread;        testfds = readfds;        printf("server waiting...\n");        result = select(FD_SETSIZE, &testfds, (fd_set *)0,             (fd_set *)0, (struct timeval *) 0);         printf("FD_SETSIZE = %d \n", FD_SETSIZE);        if(result < 1) {            perror("server5");            exit(1);        }   /*  Once we know we've got activity,    we find which descriptor it's on by checking each in turn using FD_ISSET.  */        printf("hello\n");        printf("FD_SETSIZE = %d \n", FD_SETSIZE);        for(fd = 0; fd < FD_SETSIZE; fd++) {                if(FD_ISSET(fd,&testfds)) {/*  If the activity is on server_sockfd, it must be a request for a new connection    and we add the associated client_sockfd to the descriptor set.  */                if(fd == server_sockfd) {                    client_len = sizeof(client_address);                    client_sockfd = accept(server_sockfd,                        (struct sockaddr *)&client_address, &client_len);                    FD_SET(client_sockfd, &readfds);                    printf("adding client on fd %d\n", client_sockfd);                }/*  If it isn't the server, it must be client activity.    If close is received, the client has gone away and we remove it from the descriptor set.    Otherwise, we 'serve' the client as in the previous examples.  */                else {                    ioctl(fd, FIONREAD, &nread);                    if(nread == 0) {                        close(fd);                        FD_CLR(fd, &readfds);                        printf("removing client on fd %d\n", fd);                    }                    else {                        read(fd, &ch, 1);                        printf("serving client on fd %d\n", fd);                    //    sleep(5);                        ch++;                        write(fd, &ch, 1);                    }                }            }        }    }}


原创粉丝点击