协议缓冲区、C# 和 NetworkStream:永远不会收到消息
Protocol buffers, C# and NetworkStream: messages are never received
我正在尝试在 NetworkStream
上使用 ProtocolBuffers,但消息从未被完全接收。
这是我的服务器:
var listener = new TcpListener(System.Net.IPAddress.Any, 4989);
listener.Start();
while (true)
{
var client = listener.AcceptTcpClient();
Task.Factory.StartNew(() =>
{
var message = ServerMessage.Parser.ParseFrom(client.GetStream());
Console.WriteLine(message);
});
}
这是我的客户:
Thread.Sleep(2000);//Wait for server to start
var client = new TcpClient();
client.Connect("localhost", 4989);
while (true)
{
var message = new ServerMessage
{
Time = (ulong)DateTime.UtcNow.Ticks,
Type = MessageType.Content
};
message.WriteTo(client.GetStream());
Thread.Sleep(1000);
}
此处提供完整的重现解决方案:https://github.com/IanPNewson/ProtobufNetworkStreamIssue
怎么了?
protobuf 不是终止协议,我的意思是:当单个消息结束时,字面上没有任何说明。因此,默认情况下:像 ParseFrom
这样的 API 读取 直到流结束 ,并且在打开的 Socket
/NetworkStream
中:仅当您发送一条消息然后关闭出站连接时才会发生(目前 没有更多字节 是不够的 - 它需要在流上看到实际的 EOF,这意味着每个套接字只能发送一条消息)。
因此,您通常将 framing 与 protobuf 一起使用,这意味着:在开放流中表示单个消息的某种方式。这通常是通过 length-prefix 完成的(您不能使用标记值来终止,因为 protobuf 可以包含任何字节值)。
一些 API 包括用于此的便捷方法(例如,protobuf-net 中的 *WithLengthPrefix
API,尽管您不能将其放在此处)- 或者您可以自己手动实现.或者,也许考虑像 gRPC 这样的东西,它处理所有框架等语义 为你 ,这样你就可以专注于做有趣的工作。如果您真的不想处理 gRPC 的完整 HTTP/2 方面,我有一个适用于裸套接字的 gRPC 变体。
我正在尝试在 NetworkStream
上使用 ProtocolBuffers,但消息从未被完全接收。
这是我的服务器:
var listener = new TcpListener(System.Net.IPAddress.Any, 4989);
listener.Start();
while (true)
{
var client = listener.AcceptTcpClient();
Task.Factory.StartNew(() =>
{
var message = ServerMessage.Parser.ParseFrom(client.GetStream());
Console.WriteLine(message);
});
}
这是我的客户:
Thread.Sleep(2000);//Wait for server to start
var client = new TcpClient();
client.Connect("localhost", 4989);
while (true)
{
var message = new ServerMessage
{
Time = (ulong)DateTime.UtcNow.Ticks,
Type = MessageType.Content
};
message.WriteTo(client.GetStream());
Thread.Sleep(1000);
}
此处提供完整的重现解决方案:https://github.com/IanPNewson/ProtobufNetworkStreamIssue
怎么了?
protobuf 不是终止协议,我的意思是:当单个消息结束时,字面上没有任何说明。因此,默认情况下:像 ParseFrom
这样的 API 读取 直到流结束 ,并且在打开的 Socket
/NetworkStream
中:仅当您发送一条消息然后关闭出站连接时才会发生(目前 没有更多字节 是不够的 - 它需要在流上看到实际的 EOF,这意味着每个套接字只能发送一条消息)。
因此,您通常将 framing 与 protobuf 一起使用,这意味着:在开放流中表示单个消息的某种方式。这通常是通过 length-prefix 完成的(您不能使用标记值来终止,因为 protobuf 可以包含任何字节值)。
一些 API 包括用于此的便捷方法(例如,protobuf-net 中的 *WithLengthPrefix
API,尽管您不能将其放在此处)- 或者您可以自己手动实现.或者,也许考虑像 gRPC 这样的东西,它处理所有框架等语义 为你 ,这样你就可以专注于做有趣的工作。如果您真的不想处理 gRPC 的完整 HTTP/2 方面,我有一个适用于裸套接字的 gRPC 变体。