表明是否已通过网络接收所有数据的最佳方式?

时间:2013-10-28 16:38:26

标签: c# networking tcp tcpclient tcplistener

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

目前,就网络功能而言,它远非“强大”。我试图把它拿到那里,研究让我相信我需要某种协议来确保网络传输过程中没有数据丢失。

我听说过几种方法。我认为最适合我们情况的是使用终结符,例如<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();
}

因此,考虑到这两个代码示例,如何修改这些代码以包含和检查某种数据终止符,表明可以安全地停止读取数据?

2 个答案:

答案 0 :(得分:0)

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

所以你过早地终止你的阅读循环,从而在接收者处丢失数据,并在发送者处重置。

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

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

答案 1 :(得分:0)

我们最终在项目的两端使用了EOS(流末尾)指标。我不会发布完整的代码示例,但这里有一小部分它的工作原理:

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

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