我一直在为我的某些应用程序编写小型特定用途HTTP服务器,我注意到,如果在write()
之前read()
所有可用数据,则字节不能正确发送。例如,在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:好吧,@ serbie指出了一个错字...... "Connection: close\r\r"
。修复之后,行为已经改变,变得不那么可怕了:write()
实际上根本没有发送数据。现在,Wireshark只显示请求!没有回复(来自我的write()
)。
编辑3:正如@usr所建议的,我写了一个小测试客户端...当服务器read()
在write()
之前的所有内容时,客户端始终收到所有HTTP有效负载。当服务器write()
在read()
客户端发送的标头之前,客户端从不接收整个HTTP有效负载。我做了很多测试!
当服务器write()
之后 read()
标题时
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
当服务器write()
之前 read()
标题时
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()
是标题,但总是仅显示请求,如果服务器没有read()
标题。说真的,这与TCP有关。
答案 0 :(得分:2)
在阅读请求之前,您不应该写回复。您违反了HTTP协议。
那就是说我不知道为什么浏览器会像那样。在任何情况下都停止违反HTTP协议。
TCP是双向字节流。它不关心何时和写什么。这不是TCP级问题。
我不确定我在该屏幕截图上看到了什么。如果你的意思是缺少的\n
字符肯定没有被内核剥离。内核没有业务干扰您发送的数据。它不知道数据意味着什么。
您的应用有错误。也许你正在使用一些有用的图书馆&#34;将行结尾转换为Linux格式?!无代码无法回答。这个答案与发布的信息一样好。
答案 1 :(得分:1)
您的Connection
标题以\r\r
而不是\r\n
结尾。这解释了Wireshark跟踪中的怪异。
而不是这个;
"Connection: close\r\r"
更改它:
"Connection: close\r\n"
答案 2 :(得分:-1)
嗯......好像内核有以下策略,我只是通过经验测试发现,在sleep(1)
之前加close()
。
如果没有任何内容可以read()
,并且您立即调用write()
和close()
,内核将正确发送所有内容,没问题。
但如果有read()
和你write(); close()
的内容,内核将停止发送数据,就像你刚决定突然停止对话一样。内核有点认为“嗯......他甚至没有read()
这些东西我正在抱着他正在关闭插座...他可能也希望我停止发送他告诉我发送的这些东西”。愚蠢的内核!