简体   繁体   English

C# TcpClient 从流中读取或获取不完整的数据

[英]C# TcpClient reading or getting incomplete data from stream

I have an exe which simulates a video stream.我有一个模拟视频流的 exe。 I connect to it and very occasionally read the expected data, but usually I get only the first 28 bytes and then 65508 bytes of zeros.我连接到它并偶尔读取预期的数据,但通常我只得到前 28 个字节,然后是 65508 个字节的零。 Assume the video stream is working correctly.假设视频流工作正常。

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();

How can I make it so that I get the expected output every time?我怎样才能做到这样我每次都能得到预期的输出?

TCP represents a (bi-directional) stream of data. TCP 表示(双向)数据流。 You're supposed to keep reading from it in a loop, and parsing the data as you need them.您应该在循环中继续读取它,并根据需要解析数据。 It doesn't have a concept of messages - ten writes on one side can result in a single read on the other side just as easily as one write on one side can result in ten reads on the other side.它没有消息的概念 - 一侧的十次写入可以导致另一侧的一次读取,就像一侧的一次写入可以导致另一侧的十次读取一样容易。

The contract you have with TCP is as follows:您与 TCP 的合同如下:

  • If there is data in the receive buffer, Read returns immediately, filling the buffer you provided with as much data as is available, up to the length of the buffer.如果接收缓冲区中有数据, Read立即返回,用尽可能多的可用数据填充您提供的缓冲区,直至缓冲区的长度。 The number of bytes read is the return value of Read .读取的字节数是Read的返回值。
  • If there is no data in the receive buffer, Read will block until there's at least a single byte of data.如果接收缓冲区中没有数据, Read将阻塞,直到至少有一个字节的数据。 Then it follows as in the first case.然后按照第一种情况进行。
  • If the other sides shuts down the socket, Read will return zero.如果对方关闭套接字, Read将返回零。

So to get TCP working, you need a loop.所以为了让 TCP 工作,你需要一个循环。 How exactly you form the loop depends on what you're trying to do.您如何准确地形成循环取决于您要尝试做什么。 If you're really working with data that is logically a stream (eg audio data), just keep reading as fast as you can and process whatever data you get as it comes in. If you need to send messages, you need to implement a message protocol.如果你真的在处理逻辑上是流的数据(例如音频数据),只要尽可能快地阅读并处理你获得的任何数据。如果你需要发送消息,你需要实现一个消息协议。 If you need a one-off message, you can just keep reading until Read returns zero.如果您需要一次性消息,您可以继续阅读,直到Read返回零。

Your case can be handled with the first approach - keep reading until the stream closes, and push the received data forward.您的情况可以使用第一种方法处理 - 继续阅读直到流关闭,然后将接收到的数据向前推送。 Assuming the data is actually a UTF8 stream of text, the basic receiver would look something like this:假设数据实际上是一个 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();
}

Note that this does no error handling, so don't use it as is in any production code.请注意,这不会进行错误处理,因此不要在任何生产代码中使用它。 You would probably also want to use Async methods if you're expecting more than a few simultaneous connections.如果您期望多个同时连接,您可能还想使用Async方法。 It's just to illustrate the basic way one would handle a stream of data being received over TCP.这只是为了说明处理通过 TCP 接收的数据流的基本方式。

If you want some more insight into dealing with TCP, I have a few very simple examples at https://github.com/Luaancz/Networking .如果您想更深入地了解如何处理 TCP,我在https://github.com/Luaancz/Networking 上有一些非常简单的示例。 I haven't found any good tutorials or code samples for C#, so if this isn't enough, you'll probably have to dig deeper into the documentation around sockets, TCP and all that.我还没有找到任何关于 C# 的好的教程或代码示例,所以如果这还不够,您可能需要深入研究有关套接字、TCP 和所有这些的文档。

Or just use an existing networking library, rather than trying to write your own :) TCP is still very low level.或者只是使用现有的网络库,而不是尝试编写自己的 :) TCP 仍然非常低级。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM