繁体   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