send返回值
在Unix系統(tǒng)下,如果send?、?recv?、?write在等待協(xié)議傳送數(shù)據(jù)時(shí)?,?socket?被?shutdown,調(diào)用send的進(jìn)程會(huì)接收到一個(gè)SIGPIPE信號,進(jìn)程對該信號的默認(rèn)處理是進(jìn)程終止。?此種情況?應(yīng)用就很難查?出?處理進(jìn)程為什么退出。
?
SIGPIPE?信號:
對 一個(gè)已經(jīng)收到FIN包的socket調(diào)用read方法,?如果接收緩沖已空,?則返回0,?這就是常說的表示連接關(guān)閉.?但第一次對其調(diào)用write方法 時(shí),?如果發(fā)送緩沖沒問題,?會(huì)返回正確寫入(發(fā)送).?但發(fā)送的報(bào)文會(huì)導(dǎo)致對端發(fā)送RST報(bào)文,?因?yàn)閷Χ说膕ocket已經(jīng)調(diào)用了close,?完全 關(guān)閉,?既不發(fā)送,?也不接收數(shù)據(jù).?所以,?第二次調(diào)用write方法(假設(shè)在收到RST之后),?會(huì)生成SIGPIPE信號,?導(dǎo)致進(jìn)程退出?。如果對?SIGPIPE?進(jìn)行忽略處理,?二次調(diào)用write方法時(shí),?會(huì)返回-1,?同時(shí)errno置為SIGPIPE.
處理方法:
在初始化時(shí)調(diào)用?signal(SIGPIPE,SIG_IGN)?忽略該信號(只需一次)?,?SIGPIPE交給了系統(tǒng)處理。?此時(shí)?send?、?recv?或?write?函數(shù)將返回-1,errno為EPIPE,可視情況關(guān)閉socket或其他處理????
SIGPIPE?被忽略的情況下,如果?服務(wù)器采用了fork的話,要收集垃圾進(jìn)程,防止僵尸進(jìn)程的產(chǎn)生,可以這樣處理:??signal(SIGCHLD,SIG_IGN); 交給系統(tǒng)init去回收。?這樣?子進(jìn)程就不會(huì)產(chǎn)生僵尸進(jìn)程了。
?
?
在Linux環(huán)境下開發(fā)經(jīng)常會(huì)碰到很多錯(cuò)誤(設(shè)置errno),其中EAGAIN是其中比較常見的一個(gè)錯(cuò)誤(比如用在非阻塞操作中)。
從字面上來看,是提示再試一次。這個(gè)錯(cuò)誤經(jīng)常出現(xiàn)在當(dāng)應(yīng)用程序進(jìn)行一些非阻塞(non-blocking)操作(對文件或socket)的時(shí)候。例如,以 O_NONBLOCK的標(biāo)志打開文件/socket/FIFO,如果你連續(xù)做read操作而沒有數(shù)據(jù)可讀。此時(shí)程序不會(huì)阻塞起來等待數(shù)據(jù)準(zhǔn)備就緒返 回,read函數(shù)會(huì)返回一個(gè)錯(cuò)誤EAGAIN,提示你的應(yīng)用程序現(xiàn)在沒有數(shù)據(jù)可讀請稍后再試。
又例如,當(dāng)一個(gè)系統(tǒng)調(diào)用(比如fork)因?yàn)闆]有足夠的資源(比如虛擬內(nèi)存)而執(zhí)行失敗,返回EAGAIN提示其再調(diào)用一次(也許下次就能成功)。
Linux - 非阻塞socket編程處理EAGAIN錯(cuò)誤
在linux進(jìn)行非阻塞的socket接收數(shù)據(jù)時(shí)經(jīng)常出現(xiàn)Resource temporarily unavailable,errno代碼為11(EAGAIN),這是什么意思?
這表明你在非阻塞模式下調(diào)用了阻塞操作,在該操作沒有完成就返回這個(gè)錯(cuò)誤,這個(gè)錯(cuò)誤不會(huì)破壞socket的同步,不用管它,下次循環(huán)接著recv就可以。 對非阻塞socket而言,EAGAIN不是一種錯(cuò)誤。在VxWorks和Windows上,EAGAIN的名字叫做EWOULDBLOCK。
另外,如果出現(xiàn)EINTR即errno為4,錯(cuò)誤描述Interrupted system call,操作也應(yīng)該繼續(xù)。
最后,如果recv的返回值為0,那表明連接已經(jīng)斷開,我們的接收操作也應(yīng)該結(jié)束。
當(dāng)客戶通過Socket提供的send函數(shù)發(fā)送大的數(shù)據(jù)包時(shí),就可能返回一個(gè)EGGAIN的錯(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è)置更大的值?
?
?
?
1.你自己的緩沖區(qū)滿了,會(huì)返回EAGAIN。
2.你的沒滿,對方的緩沖區(qū)滿了,肯定不關(guān)你事,可能會(huì)發(fā)送不成功,但是協(xié)議棧提供的系統(tǒng)調(diào)用,只管數(shù)據(jù)成功從你的緩沖區(qū)發(fā)出去,之后人家因?yàn)榫彌_區(qū)滿收不到數(shù)據(jù),tcp自己有重傳機(jī)制(參考Tcp/ip詳解卷1)。
?
?
?
?
send()適用于已連接的數(shù)據(jù)包或流式套接口發(fā)送數(shù)據(jù)。對于數(shù)據(jù)報(bào)類套接口,必需注意發(fā)送數(shù)據(jù)長度不應(yīng)超過通訊子網(wǎng)的IP包最大長度。IP包最大長度在WSAStartup()調(diào)用返回的WSAData的iMaxUdpDg元素中。如果數(shù)據(jù)太長無法自動(dòng)通過下層協(xié)議,則返回WSAEMSGSIZE錯(cuò)誤,數(shù)據(jù)不會(huì)被發(fā)送。
請注意成功地完成send()調(diào)用并不意味著數(shù)據(jù)傳送到達(dá)。
如果傳送系統(tǒng)的緩沖區(qū)空間不夠保存需傳送的數(shù)據(jù),除非套接口處于非阻塞I/O方式,否則send()將阻塞。對于非阻塞SOCK_STREAM類型的套接口,實(shí)際寫的數(shù)據(jù)數(shù)目可能在1到所需大小之間,其值取決于本地和遠(yuǎn)端主機(jī)的緩沖區(qū)大小??捎胹elect()調(diào)用來確定何時(shí)能夠進(jìn)一步發(fā)送數(shù)據(jù)。
總結(jié)
- 上一篇: 【rk3399】AIO-3399J Li
- 下一篇: 02-SA8155P ADB数据传输