SslStream .read() 以第一个字节返回一个数据包

Posted

技术标签:

【中文标题】SslStream .read() 以第一个字节返回一个数据包【英文标题】:SslStream .read() returns with first byte once a packet 【发布时间】:2015-07-15 13:27:53 【问题描述】:

我想从我的 SslStream 中读取数据包。

我使用 websocket 发送数据包。另外,这个函数是在我完成 WS 握手后启动的,所以它是用来读取数据帧的。

这是阅读功能:

byte[] buffer = new byte[16 * 1024];
int read;
while (true) 
    read = input.Read(buffer, 0, buffer.Length);

    Console.WriteLine("Length: " + read + " Buffer: " + GetNumberOfSlotsUsed(buffer));

    if (read <= 0) 
        ...
     else if (read < 3) 
        ...
     else 
        ...
    

一旦我收到一个数据包,这就是打印到控制台的内容:

Length: 1 Buffer: 1
Length: 57 Buffer: 57

问题出在这个函数还是浏览器发送数据包?

我用Java写的Websocket Server中的“socket.read()”函数没有问题,所以一定是C#吧?

编辑#1:

用于发送的javascript代码:

var socket = new WebSocket(serviceUrl, protocol);
socket.onopen = function () 
    socket.send(omeString);

【问题讨论】:

“它是用来读取数据帧的”,C#的Stream.Read函数不保证每次Read调用都能读取整个帧,你必须先重建帧。但是,大小为 1 很奇怪,你是如何声明 buffer 的? @ScottChamberlain 已编辑 您也可以显示发送代码吗?没关系,它是另一种语言。事实上,如果您在代码块之前执行&lt;!-- language: java --&gt;,它将将该块的代码突出显示从 C# 切换到 Java。 @ScottChamberlain 已编辑。感谢您的提示。 Java也不是客户端。我的意思是我还用 Java 编写了一个 websocket 服务器,其中“读取”部分与 C# 中的“相同”。如果我能确定哪些字节在一起,就不会介意它们被拆分。 【参考方案1】:

对于未来搜索此完全相同问题的人:

我发现一篇文章解释了这种奇怪的现象是设计使然。

将其称为“功能”似乎很奇怪。基本上(据我所知)这个改变是让 SslStream 读取和写入第一个字节,然后推送其余的。我个人认为这是一个奇怪的变化。强制传输多个数据包有点奇怪。 (我完全知道这可能会发生,在数据包可能被分段的情况下强制额外的数据包是很奇怪的。)

Link to Article


发布者 Nimbus.Hex

When ran on machine updated with KB3147458, this output is produced:
BytesRead => 1
BytesRead => 40
BytesRead => 1
BytesRead => 40
BytesRead => 1
BytesRead => 40
BytesRead => 1
BytesRead => 40
BytesRead => 1
BytesRead => 40

When ran on a machine without KB3147458, this output is produced:
BytesRead => 41
BytesRead => 41
BytesRead => 41
BytesRead => 41
BytesRead => 41

Ilia Jerebtsov 发布

我猜这更具体是由 KB3142037 引起的, 这是 MS16-065 的安全更新。这里的问题和一些 解决方法在 https://support.microsoft.com/en-us/kb/3155464 。有注册表 可用于禁用此“功能”的键。


微软发布:

嗨 Nimbus.Hex,是的,Ilia 是正确的。这是完成的行为改变 用于 MS16-065 的安全更新。周围还有更多细节 更改可在https://support.microsoft.com/en-us/kb/3155464 获得。一世 将此解决为“按设计”问候,Himadri

【讨论】:

感谢您扩展此内容。那时我认为数据包只作为“一个”发送,这增加了混乱。 不客气!遇到了类似的问题,并认为我分享了我的发现,希望下一个研究该主题的人能看到这篇文章。【参考方案2】:

TCP 不允许阅读器确定发送的块大小。写入时不存在此信息。您的应用程序协议必须能够处理数据可以并且将以任意块的形式到达的事实。

【讨论】:

但是我该如何处理“随机”块呢?令人困惑的是,它总是只有一个字节被分开。我可以处理一个,但如果它超过一个,我不知道。 您可能需要解析 Websockets 协议。它包含区分所有内容的所有必要信息。 所以你的意思是我需要等到我收到洞数据帧头,然后读取发送的数据字节(头中指定的长度)并读取下一个头......等等?【参考方案3】:

这是一个相当老的问题,但我仍然愿意贡献。

如果您使用 Tls(准确地说是 TLS 1)对流进行身份验证,则会出现此问题。如果您遵循 microsoft 指南 (https://msdn.microsoft.com/en-us/library/system.net.security.sslstream(v=vs.110).aspx),您可能会使用以下代码进行身份验证。

stream.AuthenticateAsServer(serverCertificate,false, SslProtocols.Tls, false);

正如https://support.microsoft.com/en-us/kb/3155464 中所述,由于 TLS 1 中的漏洞,流将首先获得 1 个字节,然后是其余字节。为了解决这个问题,您的程序需要有一个标记来确定消息何时停止,如 .

另一种方式是使用TLS 1.2,可以使用stream.AuthenticateAsServer(serverCertificate,false, SslProtocols.Tls12, false);

使用它,您将获得完整的消息。

【讨论】:

以上是关于SslStream .read() 以第一个字节返回一个数据包的主要内容,如果未能解决你的问题,请参考以下文章

c#SslStream的read()函数如何知道何时返回0?

SslStream 接受证书?

Java 序列化 返序列化

当作为 COM 对象访问时,SslStream 的响应不同

如何将 PFX 证书文件应用于 SslStream 套接字侦听器?

无法加载类型“System.Net.Security.SslStream”