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