如何在 TCP 套接字 C# 上接收每个有效负载的有效负载



我正在使用从服务器接收有效负载的网络流设置一个 TCP 客户端,但有时当服务器发送大量数据时,此 TCP 客户端会从下一个有效负载返回一个块

我尝试使用Socket类,并且TcpClient带有NetworkStream,并且两者的行为相同

我的代码如下所示:

TcpClient TcpClient;
NetworkStream Stream;
public void Connect_Client()
{
TcpClient = new TcpClient(Address, Port);
Thread thread_Listener = new Thread(new ThreadStart(Listener));
thread_Listener.Start();
Stream = TcpClient.GetStream();
}
private void Listener ()
{
byte[] Buffer = new byte[2048];
while (Keep_Running)
{
int RecBytes = Stream.Read(Buffer, 0, Buffer.Length);
int ReminingBytes = RecBytes;
int NextMsgPos = 0;
if (RecBytes > 0)
{
char MsgType;
while (ReminingBytes > 0)
{
byte[] BytesMsgLen = new byte[2];
BytesMsgLen [1] = Buffer[NextMsgPos];
BytesMsgLen [0] = Buffer[NextMsgPos + 1];
Int16 MsgLen = BitConverter.ToInt16(BytesMsgLen , 0);
byte[] Message = new byte[MsgLen + 2];
for(int i = 0; i < MsgLen + 2; i++)
{
Message[i] = Buffer[i + NextMsgPos];
}
Process_Message(Message);
ReminingBytes = ReminingBytes  - (MsgLen + 2);
NextMsgPos = NextMsgPos + MsgLen + 2;
}
}
}
}

问题出在 NextMsgPos 计算中,因为存在 ReminingBytes,但此 ReminingBytes 不是完整的消息

我希望该方法.Read(( 返回整个有效负载,但有时返回我一个有效载荷和下一个有效载荷的一部分

有什么方法可以保证网络流返回整个有效负载,而不是有效负载 + 下一个有效负载的块?

没有"记录"或"有效负载"的概念 - TCP 流只是一个流。如果你有一个固定字节数的面向"有效载荷"的协议,或者使用某种指示有效载荷长度的标头,你需要自己编码。它与从文件中读取相同 - 文件没有有效负载的概念 - 它是您在原始字节流上施加的协议。

你可以看看 Redis 编码协议是如何工作的RESP,并让你的消息看起来像这样:

基本上,正如@PhilipH所说,您需要有效负载的标头。

示例,假设您要发送数组,字符串和整数;您可以像下面这样定义它们:

[type symbol]+[additional data]+[ending char(s)]+[payload]+[ending char(s) ]

例:

Array*+[Length of array in bytes]+"rn"Integer
:+[Value]+"rn"String
$+[length of string]+"rn"+[string value]+"rn"

所以编码以下数组:["hello",22,"Hi"]将是:

*3rn$5rnhellorn:22rn$2rnhirn

如您所见,每个节点都有一个标头,用于指定有效负载的类型和其他基本数据(字符串的长度。等(。

然后,您将能够从流中读取包含来自不同消息的部分的数据块,并且仅在遇到标头时才对它们采取行动。

所以假设你收到:

[chunk of node 1] [full node 2] [header of node 3]
-在这种情况下,您已经存储了上一个块中节点 1 的标头,因此您知道它是什么类型以及它是如何结束的。
-然后读取节点 2 并存储它。
-您遇到节点 3 的标头,您存储它并等待下一个块填满节点 3。

相关内容

最新更新