標(biāo)題: 從緩沖上看阻塞與非阻塞socket在發(fā)送接收上的區(qū)別 [打印本頁]

作者: 51黑tt    時(shí)間: 2016-3-5 17:13
標(biāo)題: 從緩沖上看阻塞與非阻塞socket在發(fā)送接收上的區(qū)別
   最近在網(wǎng)絡(luò)上看到一些帖子以及回復(fù),同時(shí)又搜索了一些網(wǎng)絡(luò)上關(guān)于阻塞非阻塞區(qū)別的描述,發(fā)現(xiàn)很多人在描述兩者的發(fā)送接收時(shí)操作返回以及緩沖區(qū)處理的區(qū)別時(shí)有不同程度的誤解。所以我想寫一篇文章來糾正錯(cuò)誤,并作為記錄方便查閱,如有轉(zhuǎn)載,注明作者(jwybobo2007)以及出處即可。
  首先socket在默認(rèn)情況下是阻塞狀態(tài)的(未指異步操作以及其它一些特殊用途下,直接默認(rèn)為非阻塞),這就使得發(fā)送以及接收操作處于阻塞的狀態(tài),即調(diào)用不會(huì)立即返回,而是進(jìn)入睡眠等待操作完成。下面把討論點(diǎn)分為發(fā)送以及接收。
一.發(fā)送選用send(這里特指TCP)以及sendto(這里特指UDP)來描述
    首先需要說明的是,不管阻塞還是非阻塞,在發(fā)送時(shí)都會(huì)將數(shù)據(jù)從應(yīng)用緩沖區(qū)拷貝到內(nèi)核緩沖區(qū)(SO_RCVBUF選項(xiàng)聲明,除非緩沖區(qū)大小為0)。我在網(wǎng)絡(luò)上看到某些人說,阻塞就是將數(shù)據(jù)真正發(fā)送給對(duì)方,并且阻塞是發(fā)生在需要把前面的所有數(shù)據(jù)全部發(fā)送出去,然后再發(fā)送本次的,而非阻塞則是拷貝到發(fā)送緩沖區(qū)。我不得不說,上面的這種說法是錯(cuò)誤的。
    在阻塞模式下send操作將會(huì)等待所有數(shù)據(jù)均被拷貝到發(fā)送緩沖區(qū)后才會(huì)返回。
    如果當(dāng)前發(fā)送緩沖總大小為8192,已經(jīng)拷貝到緩沖的數(shù)據(jù)為8000,那剩余的大小為192,現(xiàn)在需要發(fā)送2000字節(jié)數(shù)據(jù),那阻塞發(fā)送就會(huì)等待緩沖區(qū)足夠把所有2000字節(jié)數(shù)據(jù)拷貝進(jìn)去,如第一次拷貝進(jìn)192字節(jié),當(dāng)緩沖區(qū)成功發(fā)送出1808字節(jié)后,再把應(yīng)用緩沖區(qū)剩余的1808字節(jié)拷貝到內(nèi)核緩沖,而后send操作返回成功發(fā)送字節(jié)數(shù)。
    從上面的過程不難看出,阻塞的send操作返回的發(fā)送大小,必然是你參數(shù)中的發(fā)送長度的大小。
    在阻塞模式下的sendto操作不會(huì)阻塞。
    關(guān)于這一點(diǎn)的原因在于:UDP并沒有真正的發(fā)送緩沖區(qū),它所做的只是將應(yīng)用緩沖區(qū)拷貝給下層協(xié)議棧,在此過程中加上UDP頭,IP頭,所以實(shí)際不存在阻塞。
    在非阻塞模式下send操作調(diào)用會(huì)立即返回。
    關(guān)于立即返回大家都不會(huì)有異議。還是拿阻塞send的那個(gè)例子來看,當(dāng)緩沖區(qū)只有192字節(jié),但是卻需要發(fā)送2000字節(jié)時(shí),此時(shí)調(diào)用立即返回,并得到返回值為192。從中可以看到,非阻塞send僅僅是盡自己的能力向緩沖區(qū)拷貝盡可能多的數(shù)據(jù),因此在非阻塞下send才有可能返回比你參數(shù)中的發(fā)送長度小的值。
    如果緩沖區(qū)沒有任何空間時(shí)呢?這時(shí)肯定也是立即返回,但是你會(huì)得到WSAEWOULDBLOCK/E WOULDBLOCK 的錯(cuò)誤,此時(shí)表示你無法拷貝任何數(shù)據(jù)到緩沖區(qū),你最好休息一下再嘗試發(fā)送。
    在非阻塞模式下sendto操作 不會(huì)阻塞(與阻塞一致,不作說明)。

二.接收選用recv(這里特指TCP)以及recvfrom(這里特指UDP)來描述
    在阻塞模式下recv,recvfrom操作將會(huì)阻塞 到緩沖區(qū)里有至少一個(gè)字節(jié)(TCP)或者一個(gè)完整UDP數(shù)據(jù)報(bào)才返回。
    在沒有數(shù)據(jù)到來時(shí),對(duì)它們的調(diào)用都將處于睡眠狀態(tài),不會(huì)返回。
    在非阻塞模式下recv,recvfrom操作將會(huì)立即返回。
    如果緩沖區(qū) 有任何一個(gè)字節(jié)數(shù)據(jù)(TCP)或者一個(gè)完整UDP數(shù)據(jù)報(bào),它們將會(huì)返回接收到的數(shù)據(jù)大小。而如果沒有任何數(shù)據(jù)則返回錯(cuò)誤 WSAEWOULDBLOCK/E WOULDBLOCK。

  以上是關(guān)于阻塞非阻塞發(fā)送接收的區(qū)別以及在緩沖區(qū)處理上的差別,希望給看到這篇文章的人一些幫助。同時(shí)也想糾正網(wǎng)絡(luò)上的某些錯(cuò)誤觀點(diǎn),文章中表述如有錯(cuò)誤,望大家指正,謝謝。






歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1