1

我正在编写一个TCP客户端和一个使用手动编写的HTTP请求进行通信的服务器。我遇到的麻烦是使用StreamReaderNetwork Stream读取。到目前为止,我尝试了很多方法,但无济于事。C# - 使用StreamReader读取HTTP请求

我从TCP客户端获得的请求有多种形式。为了更新数据库,则请求是这样的(CRLF是一个常数我使用表示"\r\n"字符串):

HTTP 1.0:

“POST /” +名称+“HTTP/1.0 “+ CRLF +”Content-Length:“+ length + CRLF + CRLF + location;

HTTP 1.1:

“POST/HTTP/1.1” + CRLF +主机名+ “内容长度:” +长度+ CRLF + CRLF + nameLocString;

的请求是正确的形式,并在客户端正确发送它们 - 我已经测试这一个服务器上,我有机会在答复他们没有问题。

我的问题是我的TCP侦听器代码。为了避免发布整个代码,我只包含有问题的代码部分(通过调试发现)。

Server代码:

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异常,它需要太长的时间来读/连接被强制关闭。我关掉了超时时间,而且Read的时间不确定。

由于使用ReadLine()的I能挑出它最终挂起发现,当两个CRLFs("\r\n\r\n")的集群协议和的所有版本的地方,流Reader是无法应付与此并卡住。

对于如何解决这个问题你有什么建议吗?我需要按照规范使用具有多个CRLF的版本。

如果您需要任何附加信息,我会尽量以sson的形式提供。

+0

您可以发布“无法应对此问题并卡住”的代码,因为您发布的内容对我来说工作正常。请注意,'ReadLine' [不包含任何终止退货或换行](https://msdn.microsoft.com/en-us/library/system.io.streamreader.readline%28v=vs.110%29.aspx) ,所以你发布的内容将返回所有与退货和换行连接在一起的内容。 –

+0

@DourHighArch我提供的代码是代码,它对我来说都是失败的。我检查了并且客户端正确将提到的HTTP请求写入流并刷新它们,然后当我使用任何ReadLine方法读取时,我从来没有得到超过Content-Length:+ length + CRLF + CRLF的任何内容。它会无限期地读取或在设置超时时抛出异常。感谢关于ReadLine的说明。我首先想要尽可能简单地阅读,然后看看正确的阅读。我用新的简单服务器测试了阅读(只读和回显),它也有同样的问题。 –

回答

2

最后我找到了解决我的问题的方法。除了使用

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; 
} 

我仍然不知道为什么用线读取输入没有工作,但在时间炭阅读它的时候,它的作用。

+0

谢谢你,今天你节省了我的一天:D –

1

Read操作的NetworkStream块是否有目前无可用数据,而另一侧没有关闭该通道尚未。 TCP本身没有消息的概念 - 该问题需要在HTTP级别解决。

对于HTTP,您可以继续阅读,直到您的数据包含\r\n\r\n序列,该序列将标​​题与正文分开。如何处理体取决于哪些报头存在:

  • Transfer-Encoding: chunked表示该发送方将发送数据块,并且将与长度为0的块
  • Content-Length结束应该存在时不使用块,你就可以读取数据
  • GET请求的正是许多字节不应有身体,你也许可以承担这个如果上述头部没有设置
  • Connection: close可用于响应,指示所有响应数据发送

正如你可以看到,StreamReader.ReadLine()会起到很好的解析头之后的连接将被关闭,这是很适合也可以读大块,但它不能用于阅读固定长度的身体。

我不知道从以前从StreamReader(它可能会读取一些数据到其缓冲区)读取流,但是在它们周围拍打using块只会导致底层流除非你是pick that one constructor overload

+0

我以前错了,这就是为什么我不接受你的答案。通过跟踪它,我的问题进一步向下移动。感谢您的努力,并写下我的问题的答案。 –

+0

我不介意你不接受我的答案,但是先前你评论说,这个答案启发你调用'StreamReader。关闭()'而不是使用'使用'块 - 这实际上不是我想要发送给你的方向。如果你有关于我的答案的问题,你可以评论他们,我会更新答案。 –