TCP和UDP阻塞和非阻塞之間的區別

2021-08-29 07:41:40 字數 1614 閱讀 4941

首先socket在預設情況下是阻塞狀態的,這就使得傳送以及接收操作處於阻塞的狀態,即呼叫不會立即返回,而是進入睡眠等待操作完成。下面把討論點分為傳送以及接收。

一.傳送選用send(這裡特指tcp)以及sendto(這裡特指udp)來描述

首先需要說明的是,不管阻塞還是非阻塞,在傳送時都會將資料從應用緩衝區拷貝到核心緩衝區(so_rcvbuf選項宣告,除非緩衝區大小為0)。我在網路上看到某些人說,阻塞就是將資料真正傳送給對方,並且阻塞是發生在需要把前面的所有資料全部傳送出去,然後再傳送本次的,而非阻塞則是拷貝到傳送緩衝區。我不得不說,上面的這種說法是錯誤的。

在阻塞模式下send操作將會等待所有資料均被拷貝到傳送緩衝區後才會返回。

例如:如果當前傳送緩衝總大小為8192,已經拷貝到緩衝的資料為8000,那剩餘的大小為192,現在需要傳送2000位元組資料,那阻塞傳送就會等待緩衝區足夠把所有2000位元組資料拷貝進去,如第一次拷貝進192位元組,當緩衝區成功傳送出1808位元組後,再把應用緩衝區剩餘的1808位元組拷貝到核心緩衝,而後send操作返回成功傳送位元組數。

從上面的過程不難看出,阻塞的send操作返回的傳送大小,必然是你引數中的傳送長度的大小。

man 一下 send,發現man裡有描述容易誤導,send() shall fail.應該是需要自己判斷的,會返回實際傳送成功的位元組,想全部成功傳送,需要自己實現一遍阻塞迴圈傳送的邏輯,當多埠*大包傳送的時候,可以非阻塞拆包傳送(迴圈每個埠send一次小包,避免單個埠阻塞很久),效果會比阻塞的好很多。

在阻塞模式下的sendto操作不會阻塞。

關於這一點的原因在於:udp並沒有真正的傳送緩衝區,它所做的只是將應用緩衝區拷貝給下層協議棧,在此過程中加上udp頭,ip頭,所以實際不存在阻塞。

在非阻塞模式下send操作呼叫會立即返回。

例如:當緩衝區只有192位元組,但是卻需要傳送2000位元組時,此時呼叫立即返回,並得到返回值為192。從中可以看到,非阻塞send僅僅是盡自己的能力向緩衝區拷貝盡可能多的資料,因此在非阻塞下send才有可能返回比你引數中的傳送長度小的值。

如果緩衝區沒有任何空間時呢?這時肯定也是立即返回,但是你會得到wsaewouldblock/e wouldblock的錯誤,此時表示你無法拷貝任何資料到緩衝區,你最好休息一下再嘗試傳送。

在非阻塞模式下sendto操作 不會阻塞(與阻塞一致,不作說明)。

二.接收選用recv(這裡特指tcp)以及recvfrom(這裡特指udp)來描述

在阻塞模式下recv,recvfrom操作將會阻塞到緩衝區裡有至少乙個位元組(tcp)或者乙個完整udp資料報才返回。

在沒有資料到來時,對它們的呼叫都將處於睡眠狀態,不會返回。

在非阻塞模式下recv,recvfrom操作將會立即返回。

如果緩衝區 有任何乙個位元組資料(tcp)或者乙個完整udp資料報,它們將會返回接收到的資料大小。而如果沒有任何資料則返回錯誤wsaewouldblock/e wouldblock。

TCP非阻塞accept和非阻塞connect

非阻塞accept 當乙個已完成的連線準備好被accept的時候,select會把監聽socket標記為可讀。因此,如果用select等待外來的連線時,應該不需要把監聽socket設定為非阻塞模式,因為如果select告訴我們連線已經就緒,accept就不應該被阻塞。不過這樣做的時候有乙個bug 當...

阻塞和非阻塞

在 windows 下的 socket 程式設計有兩個程式設計模型,阻塞和非阻塞。有時,他們也被叫做同步 阻 塞 和非同步 非阻塞 在 unix 中只支援阻塞模型。阻塞 indy 使用阻塞 socket 呼叫。阻塞呼叫很像乙個檔案的讀寫。當你讀資料或者寫資料時,直 到操作完成,函式才會返回。不同的是...

阻塞和非阻塞

在 windows 下的 socket 程式設計有兩個程式設計模型,阻塞和非阻塞。有時,他們也被叫做同步 阻 塞 和非同步 非阻塞 在 unix 中只支援阻塞模型。阻塞 indy 使用阻塞 socket 呼叫。阻塞呼叫很像乙個檔案的讀寫。當你讀資料或者寫資料時,直 到操作完成,函式才會返回。不同的是...