0

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];
        }    
    }
}
3
  • The sending part is wrong per the answer. Maybe the receive part is broken as well. Post the code. Commented Jun 11, 2014 at 9:44
  • Note, that it is easier to rely on standard protocols like HTTP. Sockets are very hard to use. Commented Jun 11, 2014 at 9:44
  • Actually sending and receiving part are working, I'm not searching for a way to get this stuff done. I can't use Http I am limited by my environment and requirements and policies in many many ways (WinCE) Commented Jun 12, 2014 at 7:20

1 Answer 1

2

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, e.g. 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.
Sign up to request clarification or add additional context in comments.

6 Comments

I don't see any documentation about what you say about the buffer. I think is possible that BeginSend copies data from my buffer locally and then enqueue my request. Do you have any reference?
I can get everything enqueued BEFORE the first callback is called and the first EndSend is called and everything is received correctly. This seems to prove what i say
Moreover i face the problem on the first chunk the second time my method is called (only if i don't renew buffer). Since the buffer is method-local i should not face this problem either: it is a new buffer when i call the method.
Just tried to look it up. Seems to be not explicetly written in the documentation. But neither is written that the buffer is copied. In fact the whole point of the Send method is to make a copy of your given buffer into the underlying OS buffer of the socket. If .NET would make an additional copy then it would be inefficient (everything has to be copied twice) and it would hurt circumvent flow control and the async methods would not be necessary at all.
The documentation of the underlying Win32 API explicetly mentions it: msdn.microsoft.com/de-de/library/windows/desktop/… For a Winsock application, once the WSASend function is called, the system owns these buffers and the application may not access them. This array must remain valid for the duration of the send operation.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.