简体   繁体   English

.NET,NetworkStream套接字中的TCP文件发送问题

[英]TCP File Send issue in .NET, NetworkStream Socket

I'm using the following code to send a file over tcp. 我正在使用以下代码通过tcp发送文件。

If i send many times the same file consecutively to test if it is robust, i receive the first file correctly and the other messed up. 如果我连续多次发送同一文件来测试其是否健壮,则我会正确接收第一个文件,而另一个文件会弄乱。

All messed up files have the same incorrect bytes and if i Sleep(a while) all files are transfered correctly. 所有混乱的文件具有相同的不正确字节,并且如果我睡眠(一会儿),所有文件都将正确传输。 I noticed I must instantiate a new buffer while reading my file to get everything done right. 我注意到我在读取文件时必须实例化一个新的缓冲区,以使所有操作正确完成。 But i don't get why. 但是我不明白为什么。

I fear my solution to reinstantiate a buffer could be just hiding another major problem. 我担心重新实例化缓冲区的解决方案可能只是隐藏了另一个主要问题。 Any suggestion? 有什么建议吗?

using(var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read))
{
    using(var binaryReader = new BinaryReader(fileStream))
    {
        var _sendingBuffer = new byte[BUFFER_SIZE];

        int length = (int)fileStream.Length;
        int bytesRead = 0;

        //Ensure we reached the end of the stream regardless of encoding
        while (binaryReader.BaseStream.Position != binaryReader.BaseStream.Length)
        {
            bytesRead = binaryReader.Read( _sendingBuffer, 0, _sendingBuffer.Length);

            _socket.BeginSend(_sendingBuffer, 0, bytesRead, SocketFlags.None, SendFileCallback, null);

            //without this i received some messed up data
            _sendingBuffer = new byte[BUFFER_SIZE];
        }    
    }
}

BeginSend is an asynchronous operation. BeginSend是一个异步操作。 It will only be guaranteed to be started after you call it, it won't be finished immediatly. 它只能保证在您调用它后才能启动,不会立即完成。 As long as the socket is sending the passed data, that data must not be mutated. 只要套接字正在发送传递的数据,就不得对该数据进行更改。 The end of the operation will be signaled through the AsyncCallback callback parameter. 操作结束将通过AsyncCallback回调参数发出信号。

Your problem is exactly that you mutated the transmit buffer while the transmit was still in progress. 您的问题恰恰是您在传输仍在进行时更改了传输缓冲区。 Creating a new array for each transmit call fixes this. 为每个传输调用创建一个新的数组可以解决此问题。

Other ways to fix the problem: 解决该问题的其他方法:

  • Use the blocking Socket.Send function which will block until the whole data was sent and the buffer can be reused. 使用阻塞的Socket.Send函数,该函数将阻塞直到发送完所有数据并且可以重用缓冲区为止。 This will also make your error handling much easier, because the error will not show up through the AsyncCallback . 这也将使您的错误处理更加容易,因为错误不会通过AsyncCallback
  • Make your complete program acting asynchronously, eg using C#5's async Task and async/await functionalities Therefore: 使您的完整程序异步运行,例如使用C#5的异步任务和异步/等待功能,因此:
    1. First read one part of the file asynchronously. 首先异步读取文件的一部分。
    2. When the async read finishes send it asynchronously through the socket 异步读取完成后,通过套接字异步发送
    3. When this completes and there is more data to read go back to 1. 完成后,还有更多数据要读取,请返回1。

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

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