简体   繁体   中英

TCP File Send issue in .NET, NetworkStream Socket

I'm using the following code to send a file over 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. 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.

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. This will also make your error handling much easier, because the error will not show up through the AsyncCallback .
  • Make your complete program acting asynchronously, eg using C#5's async Task and async/await functionalities Therefore:
    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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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