[英]C# - Reading HTTP requests with StreamReader
我正在用C#编写一个TCP客户端和一个服务器,它们使用手动编写的HTTP请求相互通信。 我遇到的麻烦是使用StreamReader
从Network Stream
进行读取。 到目前为止,我已经尝试了许多方法,但无济于事。
我从TCP客户端收到的请求有多种形式。 对于更新数据库,请求如下所示( CRLF是我用来表示"\\r\\n"
字符串的常量):
HTTP 1.0:
“ POST /” +名称+“ HTTP / 1.0” + CRLF +“ Content-Length:” +长度+ CRLF + CRLF +位置;
HTTP 1.1:
“ POST / HTTP / 1.1” + CRLF +主机名+“ Content-Length:” +长度+ CRLF + CRLF + nameLocString;
这些请求的格式正确,客户端正在正确发送它们-我已经在我可以访问的服务器上对该服务器进行了测试,可以对它们进行响应,而不会出现问题。
我的问题是我的TCP侦听器代码。 为了避免发布整个代码,我将仅包含有问题的代码部分(通过调试找出来)。
服务器代码:
NetworkStream socketStream = new NetworkStream(connection);
StreamReader sr = new StreamReader(socketStream);
string input = ReadAllLinesWithNull(sr); // reading version 1
string input = ReadAllLinesWithEndOfStream(sr); // reading version 2
string input = ReadAllLinesWithPeek(sr); // reading version 3
string input = sr.ReadToEnd(); // reading version 4
使用的方法是:
static string ReadAllLinesWithNull(StreamReader sr)
{
string input;
string nextLine;
input = sr.ReadLine();
while ((nextLine = sr.ReadLine()) != null)
{
Console.WriteLine(input);
input += nextLine;
}
sr.Close();
return input;
}
static string ReadAllLinesWithEndOfStream(StreamReader sr)
{
string input = "";
while (!sr.EndOfStream)
{
input += sr.ReadLine();
}
sr.Close();
return input;
}
static string ReadAllLinesWithPeek(StreamReader sr)
{
string input = "";
while (sr.Peek() >= 0)
{
input += sr.ReadLine();
}
sr.Close();
return input;
}
这些阅读方法均无效。 设置了我的连接超时后,我收到了IO异常消息,该消息读取时间太长/强行关闭了连接。 我关闭了超时,“读取”花费了不确定的时间。
多亏使用ReadLine()
我能够找出所有协议版本最终挂起的地方,并发现当存在两个CRLF( "\\r\\n\\r\\n"
)的簇时,流读者无法对此进行处理并陷入困境。
您对如何解决这个问题有任何建议吗? 我需要使用规范中包含多个CRLF的版本。
如果您需要任何其他信息,我将尽量提供合理的信息。
最后,我找到了解决问题的方法。 而不是使用
static string ReadAllLinesWithPeek(StreamReader sr)
{
string input = "";
while (sr.Peek() >= 0)
{
input += sr.ReadLine();
}
sr.Close();
return input;
}
我不得不用
static string ReadAllLinesWithPeek(StreamReader sr)
{
string input = "";
while (sr.Peek() >= 0)
{
input += (char) sr.Read();
}
return input;
}
我仍然不确定为什么按行读取输入不起作用,但是一次按char读取却可以。
如果当前没有可用数据,并且另一端尚未关闭该通道,则NetworkStream
阻止进行Read
操作。 TCP本身没有消息的概念-该问题将在HTTP级别解决。
对于HTTP,您可以继续读取,直到您的数据包含\\r\\n\\r\\n
序列为止为止,该序列将标头与正文分开。 如何处理正文取决于存在的标头:
Transfer-Encoding: chunked
表示发件人将发送数据块并将以长度为0的块结尾 Content-Length
,然后可以准确读取那么多字节的数据 Connection: close
可用于响应,指示在发送所有响应数据后将关闭连接 如您所见, StreamReader.ReadLine()
在解析标头时会很好地工作,它也非常适合读取块,但不能用于读取固定长度的正文。
我不知道从以前由StreamReader
读取的流中读取数据(它可以将一些数据提前读取到其缓冲区中)是多么可行,但是using
围绕它们的块进行拍打只会导致底层流被关闭,除非您选择一个构造函数重载 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.