recv 和 send 阻塞和非阻塞的区别
目錄
答案
深入說明
在 epoll 中的應用
總結
拓展
答案
深入說明
// 將內核接收緩沖區中的數據 copy 到應用層中用戶的 buffer 中。 int recv(int sockfd, void *buf, size_t len, int flag); // 將應用層中用戶的 buffer 中的數據 copy 到內核發送緩沖區中。 int send(int sockfd, void *buf, size_t len, int flag);1、recv?
阻塞模式下,如果內核的接收緩沖區中沒有數據時,該函數就會阻塞。
非阻塞模式下,如果內核的接收緩沖區中沒有數據時,該函數就會返回。
2、send
阻塞模式下,如果發送緩沖區剩余的空間小于要發送的數據的大小,那么該函數會阻塞。
非阻塞模式下,如果發送緩沖區剩余的空間大于要發送的數據的大小,那么該函數會返回。
在 epoll 中的應用
1、水平觸發模式(LT)
在該模式下,recv 和 send 為阻塞和非阻塞,結果是一樣的。
舉 recv 栗子來說,因為在該觸發模式下,只要內核的接收緩沖區中有數據,epoll_wait()?函數都會返回,這就導致了雖然 recv 是阻塞模式的,但是每次調用時,內核緩沖區都是有數據的,所以不會導致 recv 阻塞。當然了,當 recv 時是非阻塞的,就更不會造成阻塞情況了。同理,對于 send 也是一樣的。
2、邊沿觸發模式(LT)
在該模式下,recv 和 send 需要為非阻塞模式,不然就會有問題。
還是舉 recv 栗子來說,因為在該模式下,內核的接收緩沖區來數據了,那么 epoll_wait() 函數就會返回,但是僅僅返回一次,它可不管你是否在該次中是否完全取走了內核接收緩沖區中的數據。
在上述的前提下,recv 需要一個 while (true) 循環,保證將緩沖區中的數據取空。這就產生了一個問題,因為假如 recv 是阻塞的,那么當內核緩沖區中沒有數據時,該函數就會阻塞,這是致命的,所以 recv 必須是非阻塞的。
同理,對于 send 也是一樣的。理想情況時,終于有機會向對端發送數據了,一定要將想發的數據發盡。這就有問題了,如果是阻塞的,如果發到一半,發送緩沖區滿了,那么該函數就阻塞了,實際上要避免這種情況,所以要將該 send 設置為非阻塞的。
總結
在水平觸發模式下,recv 和 send 阻塞和非阻塞模式均可。
在邊沿觸發模式下,recv 和 send 必須為非阻塞模式。
拓展
1、將socket設置為非阻塞模式的方法。(socket設置為非阻塞的,recv 和 send 要設置為非阻塞的)
int flags = fcntl(sockfd, F_GETFL, 0); //獲取文件的flags值。fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); //設置成非阻塞模式; int n = recv(fd, pbuff, kBuffLen, MSG_DONTWAIT);?2、將socket設置為阻塞模式的方法。
int flags = fcntl(sockfd, F_GETFL, 0); //獲取文件的flags值。fcntl(sockfd, F_SETFL, flags | ~O_NONBLOCK); //設置成阻塞模式; int n = recv(fd, pbuff, kBuffLen, 0); // flag = 0,默認是阻塞的。?
(SAW:Game Over!)
總結
以上是生活随笔為你收集整理的recv 和 send 阻塞和非阻塞的区别的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: TCP/IP / UDP 头
- 下一篇: C/Cpp / STL / vector