TCP send 阻塞与非阻塞
http://blog.chinaunix.net/uid-8489474-id-2031025.html
?
tcp協(xié)議本身是可靠的,并不等于應(yīng)用程序用tcp發(fā)送數(shù)據(jù)就一定是可靠的.不管是否阻塞,send發(fā)送的大小,并不代表對端recv到多少的數(shù)據(jù).
在阻塞模式下, send函數(shù)的過程是將應(yīng)用程序請求發(fā)送的數(shù)據(jù)拷貝到發(fā)送緩存中發(fā)送就返回.但由于發(fā)送緩存的存在,表現(xiàn)為:如果發(fā)送緩存大小比請求發(fā)送的大小要大,那么send函數(shù)立即返回,同時向網(wǎng)絡(luò)中發(fā)送數(shù)據(jù);否則,send會等待接收端對之前發(fā)送數(shù)據(jù)的確認(rèn),以便騰出緩存空間容納新的待發(fā)送數(shù)據(jù),再返回(接收端協(xié)議棧只要將數(shù)據(jù)收到接收緩存中,就會確認(rèn),并不一定要等待應(yīng)用程序調(diào)用recv),如果一直沒有空間能容納待發(fā)送的數(shù)據(jù),則一直阻塞;
在非阻塞模式下,send函數(shù)的過程僅僅是將數(shù)據(jù)拷貝到協(xié)議棧的緩存區(qū)而已,如果緩存區(qū)可用空間不夠,則盡能力的拷貝,立即返回成功拷貝的大小;如緩存區(qū)可用空間為0,則返回-1,同時設(shè)置errno為EAGAIN.
?
需要注意的是,雖然將發(fā)送緩存設(shè)置成了10k,但實際上,協(xié)議棧會將其擴(kuò)大1倍,設(shè)為20k.
應(yīng)用程序表現(xiàn)如下:
在實際應(yīng)用中,如果發(fā)送端是非阻塞發(fā)送,由于網(wǎng)絡(luò)的阻塞或者接收端處理過慢,通常出現(xiàn)的情況是,發(fā)送應(yīng)用程序看起來發(fā)送了10k的數(shù)據(jù),但是只發(fā)送了2k到 對端緩存中,還有8k在本機(jī)緩存中(未發(fā)送或者未得到接收端的確認(rèn)).那么此時,接收應(yīng)用程序能夠收到的數(shù)據(jù)為2k.假如接收應(yīng)用程序調(diào)用recv函數(shù)獲 取了1k的數(shù)據(jù)在處理,在這個瞬間,發(fā)生了以下情況之一,雙方表現(xiàn)為:
A. 發(fā)送應(yīng)用程序認(rèn)為send完了10k數(shù)據(jù),關(guān)閉了socket:
發(fā)送主機(jī)作為tcp的主動關(guān)閉者,連接將處于FIN_WAIT1的半關(guān)閉狀態(tài)(等待對方的ack),并且,發(fā)送緩存中的8k數(shù)據(jù)并不清除,依然會發(fā)送給對 端.如果接收應(yīng)用程序依然在recv,那么它會收到余下的8k數(shù)據(jù)(這個前題是,接收端會在發(fā)送端FIN_WAIT1狀態(tài)超時前收到余下的8k數(shù)據(jù).), 然后得到一個對端socket被關(guān)閉的消息(recv返回0).這時,應(yīng)該進(jìn)行關(guān)閉.
B. 發(fā)送應(yīng)用程序再次調(diào)用send發(fā)送8k的數(shù)據(jù):
假如發(fā)送緩存的空間為20k,那么發(fā)送緩存可用空間為20-8=12k,大于請求發(fā)送的8k,所以send函數(shù)將數(shù)據(jù)做拷貝后,并立即返回8192;
假如發(fā)送緩存的空間為12k,那么此時發(fā)送緩存可用空間還有12-8=4k,send()會返回4096,應(yīng)用程序發(fā)現(xiàn)返回的值小于請求發(fā)送的大小值后,可以認(rèn) 為緩存區(qū)已滿,這時必須阻塞(或通過select等待下一次socket可寫的信號),如果應(yīng)用程序不理會,立即再次調(diào)用send,那么會得到-1的值, 在linux下表現(xiàn)為errno=EAGAIN.
C. 接收應(yīng)用程序在處理完1k數(shù)據(jù)后,關(guān)閉了socket:
接收主機(jī)作為主動關(guān)閉者,連接將處于FIN_WAIT1的半關(guān)閉狀態(tài)(等待對方的ack).然后,發(fā)送應(yīng)用程序會收到socket可讀的信號(通常是 select調(diào)用返回socket可讀),但在讀取時會發(fā)現(xiàn)recv函數(shù)返回0,這時應(yīng)該調(diào)用close函數(shù)來關(guān)閉socket(發(fā)送給對方ack);
如果應(yīng)用程序通過select()函數(shù)僅檢測該socket句柄是否可寫,它會返回應(yīng)用層可寫.
假設(shè)發(fā)送應(yīng)用程序收到可讀或可寫的信號后,繼
總結(jié)
以上是生活随笔為你收集整理的TCP send 阻塞与非阻塞的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LOL怎么玩
- 下一篇: 彻底学会使用epoll(一)——ET模式