linux非阻塞的socket EAGAIN的错误处理【转】
生活随笔
收集整理的這篇文章主要介紹了
linux非阻塞的socket EAGAIN的错误处理【转】
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
轉(zhuǎn)自:http://blog.csdn.net/tianmohust/article/details/8691644
版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載。 在Linux中使用非阻塞的socket的情形下。(一)發(fā)送時(shí)當(dāng)客戶通過Socket提供的send函數(shù)發(fā)送大的數(shù)據(jù)包時(shí),就可能返回一個(gè)EAGAIN的錯(cuò)誤。該錯(cuò)誤產(chǎn)生的原因是由于send 函數(shù)中的size變量大小超過了tcp_sendspace的值。tcp_sendspace定義了應(yīng)用在調(diào)用send之前能夠在kernel中緩存的數(shù)據(jù)量。當(dāng)應(yīng)用程序在socket中設(shè)置了O_NDELAY或者O_NONBLOCK屬性后,如果發(fā)送緩存被占滿,send就會(huì)返回EAGAIN的錯(cuò)誤。 為了消除該錯(cuò)誤,有三種方法可以選擇: 1.調(diào)大tcp_sendspace,使之大于send中的size參數(shù) ---no -p -o tcp_sendspace=65536 2.在調(diào)用send前,在setsockopt函數(shù)中為SNDBUF設(shè)置更大的值 3.使用write替代send,因?yàn)閣rite沒有設(shè)置O_NDELAY或者O_NONBLOCK(二)接收時(shí)接收數(shù)據(jù)時(shí)常遇到Resource temporarily unavailable的提示,errno代碼為11(EAGAIN)。這表明你在非阻塞模式下調(diào)用了阻塞操作,在該操作沒有完成就返回這個(gè)錯(cuò)誤,這個(gè)錯(cuò)誤不會(huì)破壞socket的同步,不用管它,下次循環(huán)接著recv就可以。對(duì)非阻塞socket而言,EAGAIN不是一種錯(cuò)誤。在VxWorks和Windows上,EAGAIN的名字叫做EWOULDBLOCK。其實(shí)這算不上錯(cuò)誤,只是一種異常而已。另外,如果出現(xiàn)EINTR即errno為4,錯(cuò)誤描述Interrupted system call,操作也應(yīng)該繼續(xù)。最后,如果recv的返回值為0,那表明對(duì)方已將連接斷開,我們的接收操作也應(yīng)該結(jié)束。(三)以下是另一種解釋假如發(fā)送端流量大于接收端的流量(意思是epoll所在的程序讀比轉(zhuǎn)發(fā)的socket要快),由于是非阻塞的socket,那么send()函數(shù)雖然返回,但實(shí)際緩沖區(qū)的數(shù)據(jù)并未真正發(fā)給接收端,這樣不斷的讀和發(fā),當(dāng)緩沖區(qū)滿后會(huì)產(chǎn)生EAGAIN錯(cuò)誤(參考man send),同時(shí),不理會(huì)這次請(qǐng)求發(fā)送的數(shù)據(jù).所以,需要封裝socket_send()的函數(shù)用來處理這種情況,該函數(shù)會(huì)盡量將數(shù)據(jù)寫完再返回,返回-1表示出錯(cuò)。在socket_send()內(nèi)部,當(dāng)寫緩沖已滿(send()返回-1,且errno為EAGAIN),那么會(huì)等待后再重試.這種方式并不很完美,在理論上可能會(huì)長(zhǎng)時(shí)間的阻塞在socket_send()內(nèi)部,但暫沒有更好的辦法. 這種方法類似于readn和writen的封裝(自己寫過,在《UNIX環(huán)境高級(jí)編程》中也有介紹)[cpp] view plain copysize_t socket_send(int sockfd, const char* buffer, size_t buflen) { size_t tmp; size_t total = buflen; const char *p = buffer; while(1) { tmp = send(sockfd, p, total, 0); if(tmp < 0) { // 當(dāng)send收到信號(hào)時(shí),可以繼續(xù)寫,但這里返回-1. if(errno == EINTR) { return -1; } // 當(dāng)socket是非阻塞時(shí),如返回此錯(cuò)誤,表示寫緩沖隊(duì)列已滿, // 在這里做延時(shí)后再重試. if(errno == EAGAIN) { usleep(1000); continue; } return -1; } if((size_t)tmp == total) { return buflen; } total -= tmp; p += tmp; } return tmp; }?
總結(jié)
以上是生活随笔為你收集整理的linux非阻塞的socket EAGAIN的错误处理【转】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [转]你所不知的 CSS ::befor
- 下一篇: 《影响力》承诺和一致原理深入剖析,人们对