[英]About recv and the read buffer - C Berkeley Sockets
我正在使用berkeley套接字和TCP(SOCK_STREAM套接字)。
過程是:
想象一下,我使用以下緩沖區:
char recv_buffer[3000];
recv(socket, recv_buffer, 3000, 0);
問題是:
謝謝。
如何在第一次調用recv后讀取緩沖區是否為空? 如果它不是空的,我將不得不再次調用recv,但是如果我在空的時候這樣做,我會讓它阻塞很長時間。
您可以使用select
或poll
系統調用以及套接字描述符來判斷是否有數據等待從套接字讀取。
但是,通常應該有一個由發送方和接收方都遵循的商定協議,以便雙方知道要傳輸多少數據。 例如,發送方可能首先發送一個2字節的整數,表示它將發送的字節數。 接收器然后首先讀取這個2字節的整數,以便它知道從套接字讀取多少字節。
無論如何,正如Tony在下面指出的那樣,一個健壯的應用程序應該在頭文件中使用長度信息的組合,並在每次調用recv
之前輪詢套接字以獲取其他數據(或者使用非阻塞套接字)。 這將阻止您的應用程序阻止,例如,您知道(從標題)仍然有100個字節要讀取,但對等方無法出於任何原因發送數據(也許對等計算機是意外關閉),從而導致你的recv
調用阻止。
我怎么知道我已經將多少字節重新加入recv_buffer? 我不能使用strlen,因為我收到的消息可以包含空字節。
recv
系統調用將返回讀取的字節數,如果發生錯誤,則返回-1。
從recv(2)的手冊頁:
[recv]返回接收的字節數,如果發生錯誤則返回-1。 當對等體執行有序關閉時,返回值將為0。
如何在第一次調用recv后讀取緩沖區是否為空?
即使是第一次(在接受客戶端之后),如果客戶端連接丟失,recv也會阻塞並失敗。 你必須:
select
或poll
(BSD套接字)或某些特定於操作系統的等效項,可以告訴您特定套接字描述符上是否有可用的數據(以及異常條件,以及可以寫入更多輸出的緩沖區空間) recv
只會返回任何可立即獲得的東西(可能沒有) recv
-ing數據,知道其他線程會做你擔心繼續與其他工作 我怎么知道我已經將多少字節重新加入recv_buffer? 我不能使用strlen,因為我收到的消息可以包含空字節。
recv()
返回讀取的字節數,或者出錯時返回-1。
請注意,TCP是字節流協議,這意味着您只能保證能夠以正確的順序從中讀取和寫入字節,但不保證保留消息邊界。 因此,即使發送方對其套接字進行了大量單個寫入,它也可以在路由中分段並到達幾個較小的塊,或者可以通過一個recv()
合並和檢索幾個較小的send()
/ write()
。 / read()
。
因此,請確保循環調用recv
直到獲得所需的所有數據(即可以處理的完整邏輯消息)或錯誤。 您應該准備好/能夠處理從您的客戶端獲取部分/全部后續send
(如果您沒有協議,每個方只在從另一方獲取完整消息后發送,並且不使用具有消息長度的標頭)。 請注意,對消息頭執行recvs(帶有長度),然后正文可能會導致對recv()
更多調用,從而對性能產生潛在的負面影響。
這些可靠性問題經常被忽略。 當它們在單個主機上時,它們表現得更少,可靠且快速的LAN,涉及的路由器和交換機更少,以及更少或非並發消息。 然后他們可能會在負載和更復雜的網絡上崩潰。
如果recv()
返回少於3000個字節,則可以假定讀取緩沖區為空。 如果它在3000字節緩沖區中返回3000個字節,那么您最好知道是否繼續。 大多數協議包括TLV的一些變化 - 類型,長度,值。 每條消息都包含一條消息類型的指示符,一些長度(如果長度固定,可能由類型暗示)和值。 如果在讀取您收到的數據時,您發現最后一個單元不完整,您可以假設還有更多要讀取的單元。 您還可以將套接字轉換為非阻塞套接字; 如果沒有讀取數據,則recv()
將失敗並顯示EAGAIN或EWOULDBLOCK。
recv()
函數返回讀取的字節數。
帶有FIONREAD選項的ioctl()告訴您當前可以無阻塞地讀取多少數據。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.