簡體   English   中英

在讀取所有數據之前寫入TCP套接字的行為

[英]Behavior of writing to TCP socket before reading all data

我一直在為我的某些應用程序編寫小型的專用HTTP服務器,並且我注意到,如果在read()所有可用數據之前write() ,則字節發送不正確。 例如,在read() 瀏覽器發送的請求行( GET / HTTP/1.1\\r\\n )之后,我執行write()

HTTP/1.1 200 OK\r\n
Connection: close\r\r
Content-Type: text/html\r\n
\r\n
(some HTML stuff)

Wireshark捕獲此write()

在此處輸入圖片說明

'\\n'字節和Content-Type標頭不見了! (如果存在,Wireshark總是在HTTP標頭部分顯示'\\n'字節)

並且瀏覽器不顯示HTML內容。

所以,我不應該write()read()的一切嗎? 這是TCP標准嗎?

編輯1:添加發送內容的C ++代碼:

string header =
  "HTTP/1.1 200 OK\r\n"
  "Connection: close\r\r"
  "Content-Type: text/html\r\n"
  "\r\n"
;
write(sd, header.c_str(), header.size()); // from unistd.h
FILE* fp = fopen("index.html", "rb");
char by;
while (fread(&by,1,1,fp) == 1) write(sd,&by,1);
fclose(fp);

編輯2:好吧,@ selbie指出了一個錯字... "Connection: close\\r\\r" 修復它之后,該行為已改變為一種不太可怕的行為: write()實際上根本沒有發送數據。 現在,Wireshark僅顯示請求! 沒有響應(來自我的write() )被捕獲。

編輯3:按照@usr的建議,我編寫了一個小型測試客戶端...當服務器在write()之前write() read()用作所有內容時,客戶端將始終接收所有HTTP有效負載。 當服務器執行write()之前,先執行read()客戶端發送的標頭,客戶端永遠不會收到整個HTTP有效負載。 我做了很多測試!

當服務器在頭文件的read() 之后執行 write()

HTTP/1.1 200 OK\r\n
Connection: close\r\n
Content-Type: text/html\r\n
\r\n
<form>\n
  <input type="text" name="field1" />\n
  <input type="text" name="field2" />\n
  <input type="submit" value="send" />\n
</form>\n

當服務器在標頭的read() 之前執行 write()

HTTP/1.1 200 OK\r\n
Connection: close\r\n
Content-Type: text/html\r\n
\r\n
<form>\n
  <input type="text" name="field1" />\n
  <input

和:

HTTP/1.1 200 OK\r\n
Connection: close\r\n
Content-Type: text/html\r\n
\r\n
<form>\n
  <input type="text" name="field1" />\n
  <input type="text" name="field2" />\n
  <input type="submit"

和:

HTTP/1.1 200 OK\r\n
Connection: close\r\n
Content-Type: text/html\r\n
\r\n
<form>\n
  <input type="tex

每次設置時,我都將客戶端運行50次。

為什么會這樣呢??? 必須與內核有關...

編輯4:我注意到在做這些測試的另一件事...... Wireshak 始終顯示請求和響應,如果服務器read() S中的頭部,但始終只顯示請求時,如果服務器不read()的標頭。 嚴重的是,這與TCP有關。

閱讀請求之前,您不應該編寫響應。 您違反了HTTP協議。

就是說,我不知道為什么瀏覽器會表現出這樣的行為。 無論如何都不要違反HTTP協議。

TCP是雙向字節流。 它不在乎什么時候寫什么。 這不是TCP級別的問題。

我不確定在該屏幕截圖上看到的內容。 如果您是說丟失的\\n字符,那肯定不是內核刪除的。 內核沒有業務干擾您發送的數據。 它不知道數據的含義。

您的應用存在錯誤。 也許您正在使用一些庫來“有幫助”地將行尾轉換為Linux格式? 沒有代碼就不可能回答。 這個答案與發布的信息一樣好。

您的Connection標頭以\\r\\r而不是\\r\\n結尾,這說明了Wireshark跟蹤中的怪異之處。

代替這個;

"Connection: close\r\r"

更改它,執行以下操作:

"Connection: close\r\n"

好吧……似乎內核具有以下策略,我只是通過經驗測試發現了這一策略,將sleep(1)放在close()之前。

如果沒有要read() ,並且您立即調用write()close() ,內核將正確發送所有內容,沒有問題。

但是如果有東西要read()而你write(); close() write(); close() ,內核將停止發送數據,就像您只是決定突然停止對話一樣。 內核有點想“好吧……他什至沒有read()我持有的東西,他正在關閉套接字……他可能還希望我停止發送他告訴我發送的東西”。 愚蠢的內核!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM