在读取所有数据之前写入TCP套接字的行为

时间:2016-07-31 20:09:26

标签: linux sockets http tcp

我一直在为我的某些应用程序编写小型特定用途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()

enter image description here

'\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有关。

3 个答案:

答案 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()这些东西我正在抱着他正在关闭插座...他可能也希望我停止发送他告诉我发送的这些东西”。愚蠢的内核!