2016-07-31 24 views
1

我一直在为我的某些应用程序编写小型特定目的HTTP服务器,并且我注意到,如果您在之前read()所有可用数据都未正确发送字节。例如,read()后荷兰国际集团的请求线(GET/HTTP/1.1\r\n)通过我的浏览器发送的,我write()在读取所有数据之前写入TCP套接字的行为

HTTP/1.1 200 OK\r\n 
Connection: close\r\r 
Content-Type: text/html\r\n 
\r\n 
(some HTML stuff) 

write()的Wireshark的捕获:

enter image description here

'\n'字节和Content-Type头消失了! (Wireshark在HTTP头部分总是显示'\n'字节,如果它们存在)

而浏览器不显示HTML内容。

所以我不应该在read()之前write()一切?这是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的建议,我写了一个小测试客户端...当服务器read()一切都好总是接收所有的HTTP有效载荷之前write() ING,客户端。当服务器write()s之前read() ing客户端发送的头,客户端永不接收整个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 

当服务器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="tex 

我跑客户喜欢与各设置50次。

为什么会发生这种情况?它是内核的东西...

编辑4:另一件事,我注意到做这些测试...Wireshak 总是显示请求和响应,如果服务器read()的标题,但总是只显示请求,如果服务器不read()标题。严重的是,这与TCP有关。

+0

您的连接标头以两个CR而不是CR-LF终止,这可能会让wireshark和浏览器感到困惑。 – rici

+0

我修正了这个问题,请参阅编辑。 – matheuscscp

+0

你在这里有另一个潜在的错误。你似乎没有检查你的'read'和'write'调用的返回值。由于各种原因,这些调用可能会失败并返回-1。更重要的是 - 读/写调用可以返回一个值来指示部分数据。 – selbie

回答

2

在阅读请求之前,您不应该写回应。您违反了HTTP协议。

这就是说我不知道​​为什么浏览器会表现得如此。无论如何停止违反HTTP协议。

TCP是一个双向字节流。它不关心什么时候写什么。这不是TCP级别的问题。

我不确定我在截图中看到的是什么。如果你的意思是丢失的\n字符,肯定没有被内核剥离。内核没有业务干扰您发送的数据。它不知道数据的含义。

你的应用程序有一个错误。也许你正在使用一些库来“有用地”将行结尾转换为Linux格式?无法回答没有代码。这个答案和发布的信息一样好。

+0

感谢您的回答,但是......您了解wireshark捕获的含义吗?这意味着TCP *没有*正确地发送我请求它发送的字节! *有*是TCP级别的问题。如果我发送的是完全相同的八位字节,但是在read()后面的TCP套接字中的所有字节(并且我仍然不解析这些HTTP请求字节),一切正常。所以这只是TCP问题。它不能是“我没有遵循HTTP协议”。 – matheuscscp

+0

我不确定我在截图中看到的是什么。如果你的意思是缺少\ n字符,那肯定没有被内核剥夺......你的应用程序做到了。顺便说一句,是你的低估吗? – usr

+0

我的库是C++的'std :: string'和''的'write()'。 – matheuscscp

1

您的Connection标题以\r\r而非\r\n结尾这解释了Wireshark跟踪中的奇怪现象。

取而代之,

"Connection: close\r\r" 

更改它做到这一点:

"Connection: close\r\n" 
+0

他根本看不到\ r \ n。 – usr

+0

他应该从修正他的错字开始。我相当确定这将清除他的大部分问题。 – selbie

+0

会是一个有趣的解释。我也不相信Wireshark。 – usr

-1

嗯......好像内核具有以下政策,我发现只能通过实证检验,把一个sleep(1)之前close()

如果没有什么是read(),并且您立即调用write()close(),内核将正确发送所有内容,没有问题。

但是如果有东西是read()而你write(); close(),内核将停止发送数据,就像你刚决定突然停止对话一样。内核有点认为“呃......他甚至没有我持有的东西,他正在关闭套接字......他可能也希望我停止发送他告诉我发送的这些东西。”愚蠢的内核!

+0

没有什么愚蠢的。 TCP(不是'内核')会在连接有待读取的数据时将其关闭。这是明确的行为。这里愚蠢的是以各种方式违反HTTP协议,从忽略请求开始。 – EJP

+0

我没有违反HTTP。我正在问一个关于我的家庭实验的问题,以便我自己学习。 TCP通过什么方式并不重要。正如你所提到的,观察到的行为总会发生,即使没有实施应用程序级协议。正如标题所述,问题在于TCP,而不是HTTP。所以......愚蠢的是,尽管基于实证测试(由于缺乏关于TCP的理论知识),所以这是一个正确的解决方案,可以“解决我的问题”。它**是内核重置连接,因为**内核**实现了TCP。 – matheuscscp

+1

在您阅读之前,您没有提到您的问题是您正在关闭连接。这只是错误的,任何有关套接字编程的好文本都会解释它。 – rici