複用IO還有一種就是select模型,咱們下面就來簡單介紹一下select用法。socket
int select(int maxfdp, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout);
//fd_set是一個集合,裏面存放的是文件描述符,以下是一些能夠操做fd_set的宏:
fd_set set;
FD_ZERO(&set); //清空set
FD_SET(fd, &set); //將fd加入set
FD_CLR(fd, &set); //將fd從set中清除
FD_ISSET(fd, &set); //若是fd在set中則爲真,一般用來檢查某個文件描述符是否在描述符集合中,而後去讀、寫、接收鏈接
複製代碼
struct timeval則表明超時時間,有兩個成員,一個是秒數,一個是毫秒; select參數說明:函數
socket()/bind()/listen()/select()/send()/recv()/close()ui
使用select也需先將socket設置爲非阻塞的 下面演示如何使用select函數:spa
struct timeval TimeOut, *pTimeOut = NULL;
fd_set readfds, writefds;
FD_ZERO (&readfds);
FD_SET (m_nSock, &readfds);
writefds = readfds;
TimeOut.tv_sec = 5;
TimeOut.tv_usec=0;
pTimeOut = &TimeOut;
while(1)
{
if ((nRetVal = select (m_nSock + 1,&readfds, &writefds, NULL, pTimeOut)) == 0)
{
//超時
return 0;
}
else if ((nRetVal < 0) && (errno == EINTR || errno == EPIPE))
continue;
}
複製代碼
若是鏈接斷開了,select會返回1,但單純的select返回1並不能說明鏈接斷開了,也多是有數據可讀,因此此時須要再判斷一下read或者recv的返回值,若是返回0,就說明鏈接斷開了。 僞代碼以下:指針
fd_set read_set;
struct timeval t_o;
FD_ZERO(&read_set);
FD_SET(lSockFd,&read_set);
t_o.tv_sec = n;/* 超時秒數*/
ret = select(lSockFd + 1,&read_set,NULL,NULL,&t_o);
if(ret == 1)
{
count = recv(lSockFd,buf,LEN,0);
if((count == 0))
{
//說明鏈接斷開
}
}
複製代碼