[英]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.