关于select的tcp回射服务器模型如下
#include "unp.h"
#define MAXLINE 4096
int main(int argc, char **argv)
{
char sendbuf[MAXLINE], recvbuf[MAXLINE];
int listenfd, maxfd,clientfd, sockfd;
int maxi = 0, i;
int client[FD_SETSIZE];
size_t n;
fd_set rset, allset;
int readnum;
FD_ZERO(&rset);
FD_ZERO(&allset);
for(i = 0; i < FD_SETSIZE; ++i){
client[i] = -1;
}
listenfd = Socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in seraddr, cliaddr;
bzero(&seraddr, sizeof(seraddr));
seraddr.sin_family = AF_INET;
seraddr.sin_addr.s_addr = htonl(INADDR_ANY);
seraddr.sin_port = htonl(SERV_PORT);
Bind(listenfd, (struct sockaddr *)&seraddr, sizeof(seraddr));
Listen(listenfd, LISTENQ);
maxi = 0;
FD_SET(listenfd, &allset);
for(;;){
rset = allset;
readnum = Select(maxfd + 1, &rset, NULL, NULL, NULL);
if(FD_ISSET(listenfd, &rset)){
socklen_t clilen = sizeof(cliaddr);
clientfd = Accept(listenfd, (struct sockaddr *)& cliaddr, &clilen);
for(i = 0; i < FD_SETSIZE;++i){
if(client[i] < 0){
client[i] = clientfd;
break;
}
}
if(i == FD_SETSIZE)
printf("client link too many\n");
/* std::cout << "client link too many\n";*/
FD_SET(clientfd, &allset);
if(i > maxi){
maxi = i;
}
if(clientfd > maxfd){
maxfd = clientfd;
}
if(--readnum <= 0) continue;
}
for(i = 0; i <= maxi; ++i){
if(client[i] != -1 && FD_ISSET(client[i], &rset)){
sockfd = client[i];
if((n = Readline(sockfd, recvbuf, MAXLINE)) == 0){
FD_CLR(sockfd, &allset);
Close(sockfd);
client[i] = -1;
} else{
Write(sockfd, recvbuf, n);
}
if(--readnum <= 0) break;
}
}
}
return 0;
}
1.首先的初始化监听套接字描述符,把fd_set中对应的套接字描述符,设置为1,然后进入监听程序,当有新的cilent连接的时候,select监听的套接字描述符将会变成可读的状态,然后进入可读程序。
2.Select函数中第2-4个参数,都是属于值-结果类型,最后一个参数为NULL, Select函数将会永远堵塞于改程序处,除非遇到捕捉到系统信号,而中断并且errno置于EINTR,又或者是某个描述符变成可读状态
3.第34行都51行的代码,首先检查client数组中最低位为-1的位置,将其已经连接的套接字描述符记录下来。然后检查更新maxi和最大的套接字描述符。
过程如下所示
4.第55行到66行的代码,对来至client发送的信息进行处理,首先我们对每个fd进行检验(先检查,该位置是否有连接,然后通过调用FD_ISSET函数进行检验该套接字描述符是否可读),如果读到的数据等于0.那么则表示收到了来之client的FIN分节,则选择将该描述符从fd_set结构中取出,然后关闭套接字描述符,同时把client中该套接字描述符对应位置上面的值置为-1.
5.在全过程还有一个不容忽略的值就是readnum,他表示fd_set结构中,可读的描述符号的数量,每次处理完一个对应的描述符过后都必须对其进行--操作