最近我开始使用套接字。我意识到,当从网络流中读取时,您无法知道有多少数据正在进入。所以要么您事先知道需要多少字节,要么您知道哪些字节< /强>
由于我目前正在尝试实现C#WebSocket服务器,因此我需要处理HTTP请求。 HTTP请求可以具有任意长度,因此事先知道多少字节是不可能的。但HTTP请求始终具有certain format。它从请求行开始,后跟零个或多个标题等。所以这些信息应该很简单,对吧?
不。
我提出的一种方法是读取所有数据,直到识别出特定的字节序列。 StreamReader class有ReadLine
方法,我相信这样做的方法就是这样。对于HTTP,合理的分隔符将是空行将消息头与正文分开。
这里显而易见的问题是需要一个(最好是短的)终止序列,比如换行符。甚至HTTP规范也表明这两个相邻的CRLF不是一个好的选择,因为它们也可能出现在消息的开头。毕竟,无论如何,两个CRLF都不是简单的分隔符。
因此,将方法扩展为任意类型3语法,我总结出解析数据的最佳选择是有限状态机。我可以在数据字节之后将数据提供给机器,就像我从网络流中读取数据一样。一旦机器接受输入,我就可以停止读取数据。此外,FSM可以立即捕获重要的令牌。
但这真的是最好的解决方案吗?逐字节读取并使用自定义解析器验证它看起来既乏味又昂贵。 FSM可能会很慢或很难看。所以......
当表单已知但不是大小时,如何处理来自网络流的数据?
HttpListener这样的课程如何解析邮件并快速处理?
我在这里错过了什么吗?通常如何做到这一点?
答案 0 :(得分:3)
HttpListener
和其他此类组件可以解析消息,因为格式是确定性的。请求is well documented。请求标头是一系列CRLF终止的行,后跟一个空行(连续两个CRLF)。
消息正文可能难以解析,但它的确定性在于标题会告诉您使用了什么编码,是否已经压缩等等。即使是多部分消息也不是很难解析。
是的,您需要一台状态机来解析HTTP消息。是的,你必须逐字节解析它。它有点牵扯,但速度非常快。通常,您将流中的一堆数据读入缓冲区,然后逐字节处理该缓冲区。您不会一次读取一个字节的流,因为开销会导致性能下降。
您应该查看HttpListener
源代码,看看它是如何工作的。转到http://referencesource.microsoft.com/netframework.aspx并下载.NET 4.5 Update 1源。
准备花费大量时间深入研究并通过HTTP规范。
顺便说一下,创建一个处理一小部分HTTP请求的程序并不困难。但我想知道为什么当你只能使用HttpListener
并为你处理所有细节时,你想要这样做。
您正在谈论两种不同的协议。 HTTP和WebSocket是两个完全不同的东西。正如维基百科的文章所说:
WebSocket协议是一种独立的基于TCP的协议。它与HTTP的唯一关系是它的握手被HTTP服务器解释为升级请求。
使用HTTP,您知道服务器将发送流然后关闭连接;它是一个带有定义结束的字节流。 WebSocket是一种基于消息的协议;它启用了一组消息。必须以某种方式描述这些信息;发送方必须告诉接收方消息的结尾。这可以是隐含的或明确的。有几种不同的方法:
无论如何,发件人和收件人必须就如何构建邮件达成一致。否则你担心的情况会突然出现:接收器等待永远不会收到的字节。
为了处理可能的通信问题,您在套接字上设置ReceiveTimeout属性,以便Read
如果收到完整的消息需要很长时间,则会抛出SocketException
。这样,您的程序将无法无限期地等待即将到来的数据。但这应该只发生在通信问题上。任何合理的消息格式都将包括确定消息长度的方法;要么你知道有多少数据,要么你知道什么时候你已经到达消息的末尾。
答案 1 :(得分:0)
如果您想发送消息,可以将消息的大小预先添加到消息中。获取消息中的字节数,预先将ulong挂起。在接收器,读取ulong的大小,解析它,然后从流中读取该字节数,然后关闭它。
在HTTP标头中,您可以读取:Content-Length请求正文的长度,以八位字节为单位(8位字节)