C# TcpClient 从流中读取或获取不完整的数据
C# TcpClient reading or getting incomplete data from stream
我有一个模拟视频流的exe。我连接到它并偶尔读取预期的数据,但通常我只得到前 28 个字节,然后是 65508 个字节的零。假设视频流工作正常。
TcpClient tcpClient = new TcpClient ();
int port = 13000;
myIP = IPAddress.Loopback.ToString();
tcpClient.Connect (myIP, port);
NetworkStream netStream = tcpClient.GetStream ();
byte[] bytes = new byte[tcpClient.ReceiveBufferSize];
netStream.Read (bytes, 0, (int)tcpClient.ReceiveBufferSize);
string dataString = Encoding.ASCII.GetString (bytes);
Console.WriteLine("\ndataString: "+dataString.Substring(0,1000));
Console.WriteLine("\nnumber of bytes read: "+bytes.Length);
tcpClient.Close ();
// Closing the tcpClient instance does not close the network stream.
netStream.Close();
我怎样才能每次都获得预期的输出?
TCP 表示(双向)数据流。您应该循环读取它,并根据需要解析数据。它没有 messages 的概念 - 一侧写入十次可以导致另一侧读取一次,就像一侧写入一次可以导致另一侧读取十次一样容易另一边。
您与TCP的合约如下:
- 如果接收缓冲区中有数据,
Read
return 会立即向您提供的缓冲区填充尽可能多的可用数据,直至缓冲区的长度。读取的字节数是Read
的return值。
- 如果接收缓冲区中没有数据,
Read
将阻塞,直到至少有一个字节的数据。然后跟第一种情况一样。
- 如果对方关闭套接字,
Read
将return归零。
因此,要使 TCP 正常工作,您需要一个循环。你如何准确地形成循环取决于你想做什么。如果你真的在处理逻辑上是流的数据(例如音频数据),只要尽可能快地阅读并处理你收到的任何数据。如果你需要发送消息,你需要实现一个消息协议。如果您需要一次性消息,您可以继续阅读直到 Read
return 为零。
您的情况可以用第一种方法处理 - 继续阅读直到流关闭,然后将接收到的数据向前推送。假设数据实际上是一个 UTF8 文本流,基本的接收器看起来像这样:
using (var client = new TcpClient())
{
tcpClient.Connect(myIP, port);
var stream = client.GetStream();
var buffer = new byte[4096]; // Adapt the size based on what you want to do with the data
var charBuffer = new char[4096];
var decoder = Encoding.UTF8.GetDecoder();
int bytesRead;
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0)
{
var expectedChars = decoder.GetCharCount(buffer, 0, bytesRead);
if (charBuffer.Length < expectedChars) charBuffer = new char[expectedChars];
var charCount = decoder.GetChars(buffer, 0, bytesRead, charBuffer, 0);
Console.Write(new string(charBuffer, 0, charCount));
}
client.Close();
}
请注意,这不会进行任何错误处理,因此不要像在任何生产代码中那样使用它。如果您希望有多个并发连接,您可能还想使用 Async
方法。这只是为了说明处理通过 TCP 接收的数据流的基本方式。
如果您想更深入地了解如何处理 TCP,我在 https://github.com/Luaancz/Networking 提供了一些非常简单的示例。我还没有找到任何好的 C# 教程或代码示例,所以如果这还不够,您可能需要更深入地研究有关套接字、TCP 等的文档。
或者只使用现有的网络库,而不是尝试编写自己的 :) TCP 仍然非常 低级别。
我有一个模拟视频流的exe。我连接到它并偶尔读取预期的数据,但通常我只得到前 28 个字节,然后是 65508 个字节的零。假设视频流工作正常。
TcpClient tcpClient = new TcpClient ();
int port = 13000;
myIP = IPAddress.Loopback.ToString();
tcpClient.Connect (myIP, port);
NetworkStream netStream = tcpClient.GetStream ();
byte[] bytes = new byte[tcpClient.ReceiveBufferSize];
netStream.Read (bytes, 0, (int)tcpClient.ReceiveBufferSize);
string dataString = Encoding.ASCII.GetString (bytes);
Console.WriteLine("\ndataString: "+dataString.Substring(0,1000));
Console.WriteLine("\nnumber of bytes read: "+bytes.Length);
tcpClient.Close ();
// Closing the tcpClient instance does not close the network stream.
netStream.Close();
我怎样才能每次都获得预期的输出?
TCP 表示(双向)数据流。您应该循环读取它,并根据需要解析数据。它没有 messages 的概念 - 一侧写入十次可以导致另一侧读取一次,就像一侧写入一次可以导致另一侧读取十次一样容易另一边。
您与TCP的合约如下:
- 如果接收缓冲区中有数据,
Read
return 会立即向您提供的缓冲区填充尽可能多的可用数据,直至缓冲区的长度。读取的字节数是Read
的return值。 - 如果接收缓冲区中没有数据,
Read
将阻塞,直到至少有一个字节的数据。然后跟第一种情况一样。 - 如果对方关闭套接字,
Read
将return归零。
因此,要使 TCP 正常工作,您需要一个循环。你如何准确地形成循环取决于你想做什么。如果你真的在处理逻辑上是流的数据(例如音频数据),只要尽可能快地阅读并处理你收到的任何数据。如果你需要发送消息,你需要实现一个消息协议。如果您需要一次性消息,您可以继续阅读直到 Read
return 为零。
您的情况可以用第一种方法处理 - 继续阅读直到流关闭,然后将接收到的数据向前推送。假设数据实际上是一个 UTF8 文本流,基本的接收器看起来像这样:
using (var client = new TcpClient())
{
tcpClient.Connect(myIP, port);
var stream = client.GetStream();
var buffer = new byte[4096]; // Adapt the size based on what you want to do with the data
var charBuffer = new char[4096];
var decoder = Encoding.UTF8.GetDecoder();
int bytesRead;
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0)
{
var expectedChars = decoder.GetCharCount(buffer, 0, bytesRead);
if (charBuffer.Length < expectedChars) charBuffer = new char[expectedChars];
var charCount = decoder.GetChars(buffer, 0, bytesRead, charBuffer, 0);
Console.Write(new string(charBuffer, 0, charCount));
}
client.Close();
}
请注意,这不会进行任何错误处理,因此不要像在任何生产代码中那样使用它。如果您希望有多个并发连接,您可能还想使用 Async
方法。这只是为了说明处理通过 TCP 接收的数据流的基本方式。
如果您想更深入地了解如何处理 TCP,我在 https://github.com/Luaancz/Networking 提供了一些非常简单的示例。我还没有找到任何好的 C# 教程或代码示例,所以如果这还不够,您可能需要更深入地研究有关套接字、TCP 等的文档。
或者只使用现有的网络库,而不是尝试编写自己的 :) TCP 仍然非常 低级别。