Linux Socket - 內核非阻塞功能
select 函數
int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval*timeout);
fd_set * readfds
需要監視變化的文件描述符
只要有一個文件可讀就返回>0
沒有文件可讀
超出timeout時間,返回=0
發生錯誤返回負值
傳入NULL表示不關心任何文件
fd_set * readfds
需要監視變化的文件描述符 只要有一個文件可寫就返回>0 沒有文件可讀 超出timeout時間,返回=0 發生錯誤返回負值 傳入NULL表示不關心任何文件
fd_set * errorfds
同上:監視異常文件
struct timeval* timeout
select的超時時間
為NULL時:select置於阻塞狀態
直到監視文件發生變化位置
為0s0ms時:select變為純非阻塞函數
不管文件描述符是否變化都立刻返回
有變化返回正數
無變化返回0
大於0時為等待的超時時間
select在timeout內阻塞
返回值
有可讀文件:表示可讀文件的數量 返回值>0
沒有可讀文件:判斷timeout參數超時
超出timeout時間後 返回值=0
FD_ZERO
清空文件描述符集
FD_SET
在文件描述符集合中增加一個新的
FD_CLR
刪除一個文件描述符
FD_ISSET
測試指定的文件描述符是否在集合中
SOCKET函數
int socket(int domain, int type, int protocol);
int sockfd=socket(AP_INET, SOCK_STREAM | SOCK_NOBLOCK, IPPROTO_TCP);
ACCEPT函數
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags); flags: SOCK_NOBLOCK SOCK_CLOEXEC
FCNTL函數
fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) | O_NONBLOCK);
IOCTL函數
ioctl(sockfd, FIONBIO, 1);//1:非阻塞 0:阻塞
accept,connect,recv(recvfrom),send(sendto),closesocket,select(poll或epoll)
1)accept在阻塞模式下,沒有新連接時,線程會進入睡眠狀態;非阻塞模式下,沒有新連接時,立即返回WOULDBLOCK錯誤。
2)connect在阻塞模式下,僅TCP連接建立成功或出錯時才返回,分幾種具體的情況,這裏不再敘述;非阻塞模式下,該函數會立即返回INPROCESS錯誤(需用select檢測該連接是否建立成功)
3)recv/recvfrom/send/sendto很好理解,因為這兩類函數讀寫socket文件描述符的接收/發送緩沖區。
4) select/poll/epoll並不是真正意義上的阻塞,它們的阻塞是由於它們最後一個timeout參數決定的,timeout大於0時,它們會一直等待直到超時才退出(相等於阻塞了吧,^_^),而timeout=-1即永遠等待。
5)closesocket也不是真正意義上的阻塞,它其實是指是否等待關閉。它受套接字選項SO_LINGER和SO_DONTLINGER的影響。
若SO_DONTLINGER或SO_LINGER的間隔=0時,closesocket就是非等待關閉的,但是當SO_LINGER的間隔>0時,closesoket就是等待關閉的,直到剩余數據都發送完畢或直到超時才退出。
(但是這個地方只有對於阻塞的套接口才有用,如果是非阻塞的套接口,它會立即返回並且指示錯誤WOULDBLOCK)。
Linux Socket - 內核非阻塞功能