select的实现是通过对设备的轮询来实现的,每次调用FD_ISSET()函数后 ,会把原来待检测的但是仍没就绪的描述字清0了。所以,每次调用select()前要重新调用FD_SET()来设置一下待检测的描述设备。
select()的基本知识:
select原型: int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
和select相关的宏如下:
<span style="font-size:18px;">#include<sys\select.h> void FD_SET(int fd, fd_set *fdset); void FD_CLR(int fd, fd_set *fdset); void FD_ISSET(int fd, fd_set *fdset); void FD_ZERO(fd_set *fdset);</span>
理解select模型的关键在于理解fd_set,为说明方便,取fd_set长度为1字节,fd_set中的每一bit可以对应一个文件描述符fd。则1字节长的fd_set最大可以对应8个fd。(实际当中,FD_SET中可以存放1024个文件描述符)
(5)若fd=1,fd=2上都发生可读事件,则select返回,此时set变为0000,0011。注意:没有事件发生的fd=5被清空。
案列:
这是我用select函数改进的client.cpp程序,里面select要捕获两个文件描述符,分别是,stdin(等待键盘输入),read(等待服务器端发送数据过来)。
/**************** @data: 2015/7/18 @authour:shaosli @function: this is a client **************************/ #include "net.h" int main() { int sock; sock = socket( AF_INET, SOCK_STREAM,0 ); //create a socket stream if( sock< 0 ) hand_error( "socket_create"); struct sockaddr_in my_addr; //memset my_addr; memset(&my_addr, 0, sizeof(my_addr)); my_addr.sin_family = AF_INET; my_addr.sin_port = htons(5188); //here is host sequeue //my_addr.sin_addr.s_addr = htonl( INADDR_ANY ); my_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); int conn = connect(sock, (struct sockaddr *)&my_addr, sizeof(my_addr)) ; if(conn != 0) hand_error("accept"); char recvbuf[1024] = {0}; char sendbuf[1024] = {0}; fd_set rset; FD_ZERO(&rset); int nready = 0; int maxfd; int stdinof = fileno(stdin); if( stdinof > sock) maxfd = stdinof; else maxfd = sock; while(1) { //select返回后把原来待检测的但是仍没就绪的描述字清0了。所以每次调用select前都要重新设置一下待检测的描述字 FD_SET(sock, &rset); FD_SET(stdinof, &rset); nready = select(maxfd+1, &rset, NULL, NULL, NULL); cout<<"nready = "<<nready<<endl; if(nready == -1 ) break; else if( nready == 0) continue; else { if( FD_ISSET(sock, &rset) ) //sock IO { int ret = read( sock, recvbuf, sizeof(recvbuf)); if( ret == -1) hand_error("read"); else if( ret == 0) { cout<<"sever have close"<<endl; close(sock); break; } else { fputs(recvbuf,stdout); memset(recvbuf, 0, strlen(recvbuf)); } } if( FD_ISSET(stdinof, &rset)) { if(fgets(sendbuf, sizeof(sendbuf), stdin) != NULL) { int num = write(sock, sendbuf, strlen(sendbuf)); memset(sendbuf, 0, sizeof(sendbuf)); } } } } return 0; }