指示所有数据已通过网络接收的最佳方法



我有一个运行良好的客户端/服务器应用程序,但它缺少一个关键的行为来使其更加可靠。

目前,就网络功能而言,它远非"强大"。我正在努力实现它,研究使我相信我需要某种协议来确保在网络传输过程中不会丢失任何数据。

我听说过几种方法。我认为最适合我们情况的一种是使用终结者,类似于<EOF>标签。我的问题是我不确定实现这一点的最佳方法。

这里有几个代码片段,我将在找出最佳解决方案后对其进行修改以包含终止符。

客户:

TcpClient client = new TcpClient();
client.Connect(hostname, portNo);
using (var stream = client.GetStream())
{
    //send request
    stream.Write(data, 0, data.Length);
    stream.Flush();
    //read server response
    if (stream.CanRead)
    {
        byte[] buffer = new byte[1024];
        string response = "";
        int bytesRead = 0;
        do
        {
            bytesRead = stream.Read(buffer, 0, buffer.Length);
            response += Encoding.ASCII.GetString(buffer, 0, bytesRead);
        } //trying to replace 'DataAvailable', it doesn't work well
        while (stream.DataAvailable); 
    }
}

请注意,我正在尝试替换检查流中更多数据的stream.DataAvailable方法。它一直在造成问题。

服务器:

var listener = new TcpListener(IPAddress.Any, portNo);
listener.Start();
var client = listener.AcceptTcpClient();
using (var stream = client.GetStream())
{
    var ms = new System.IO.MemoryStream();
    byte[] buffer = new byte[4096];
    int bytesRead = 0;
    do
    {
        bytesRead = stream.Read(buffer, 0, buffer.Length);
        ms.Write(buffer, 0, bytesRead);
    } //also trying to replace this 'stream.DataAvailable'
    while (stream.DataAvailable);
    ms.Position = 0;
    string requestString = Encoding.UTF8.GetString(ms.ToArray());
    ms.Position = 0;
    /*
        process request and create 'response'
    */
    byte[] responseBytes = Encoding.UTF8.GetBytes(response);
    stream.Write(responseBytes, 0, responseBytes.Length);
    stream.Flush();
}

那么,鉴于这两个代码示例,我如何修改它们以包含和检查某种指示停止读取数据是安全的数据终止符?

您可以依靠 TCP 在 FIN 之前传输所有数据。代码的问题在于 available() 不是流结束的有效测试。这是对现在可用的数据的测试。

因此,您过早地终止了读取循环,从而在接收器处丢失了数据,并在发送端重置了数据。

你应该在 Read() 方法中阻塞,直到你从 API 收到 EOS 指示,无论 C# 中是什么。

您不需要自己的额外EOS指标。

我们最终在项目的两端都使用了EOS(流结束)指示器。我不会发布完整的代码示例,但这里有一小部分它是如何工作的:

stream.Write(data, 0, data.Length);
stream.WriteByte(Convert.ToByte(ConsoleKey.Escape));
stream.Flush();

在此流的接收端,循环逐字节读取数据。一旦收到ConsoleKey.Escape字节,它就会终止循环。它有效!

相关内容

最新更新