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