Search code examples
c#socketsasyncsocket

C# Socket ReceiveAsync


I am used to sync sockets and had a few headaches to get to the point where I am now, especially with Socket.Receive(..) not always receiveing all bytes

Here is my code what I used to use

    public byte[] Receive(int size)
    {
        var buffer = new byte[size];
        var r = 0;
        do
        {
            // ReSharper disable once InconsistentlySynchronizedField
            var c = _clientSocket.Receive(buffer, r, size - r, SocketFlags.None);
            if (c == 0)
            {
                throw new SocketExtendedException();
            }
            r += c;
        } while (r != buffer.Length);
        return buffer;
    }

Now I started to use sockets in Windows Phone BUT .Receive(..) is not available and I managed to get Socket.ReceiveAsync(..) working but I am concerned (no problems happened so far) here is my new code, I have not implemented the checking if all bytes has been recieved or not nor do I know if I have to with the following code

    private byte[] ReadBySize(int size = 4)
    {
        var readEvent = new AutoResetEvent(false);
        var buffer = new byte[size];
        var recieveArgs = new SocketAsyncEventArgs()
        {
            UserToken = readEvent
        };
        recieveArgs.SetBuffer(buffer, 0, size);
        recieveArgs.Completed += recieveArgs_Completed;
        _connecter.ReceiveAsync(recieveArgs);
        readEvent.WaitOne();

        if (recieveArgs.BytesTransferred == 0)
        {
            if (recieveArgs.SocketError != SocketError.Success)
                throw new SocketException((int)recieveArgs.SocketError);
            throw new CommunicationException();
        }
        return buffer;
    }

    void recieveArgs_Completed(object sender, SocketAsyncEventArgs e)
    {
        var are = (AutoResetEvent)e.UserToken;
        are.Set();
    }

This is my first use of ReceiveAsync can someone point out anything I might have done wrong or need to change


Solution

  • Ok I went and took a large buffer and send it in batches with a sleep interval in between to replicate 'not all bytes received' So my code above doesn't recieve all bytes. for those who also use ReceiveAsync(..) here is my code that works

        private byte[] ReadBySize(int size = 4)
        {
            var readEvent = new AutoResetEvent(false);
            var buffer = new byte[size]; //Receive buffer
            var totalRecieved = 0;
            do
            {
                var recieveArgs = new SocketAsyncEventArgs()
                {
                    UserToken = readEvent
                };
                recieveArgs.SetBuffer(buffer, totalRecieved, size - totalRecieved);//Receive bytes from x to total - x, x is the number of bytes already recieved
                recieveArgs.Completed += recieveArgs_Completed;
                _connecter.ReceiveAsync(recieveArgs);
                readEvent.WaitOne();//Wait for recieve
    
                if (recieveArgs.BytesTransferred == 0)//If now bytes are recieved then there is an error
                {
                    if (recieveArgs.SocketError != SocketError.Success)
                        throw new ReadException(ReadExceptionCode.UnexpectedDisconnect,"Unexpected Disconnect");
                    throw new ReadException(ReadExceptionCode.DisconnectGracefully);
                }
                totalRecieved += recieveArgs.BytesTransferred;
    
            } while (totalRecieved != size);//Check if all bytes has been received
            return buffer;
        }
    
        void recieveArgs_Completed(object sender, SocketAsyncEventArgs e)
        {
            var are = (AutoResetEvent)e.UserToken;
            are.Set();
        }
    

    The way I work with my Socket applications is to send a Buffer that consist of some variables

    [0] -> 0,1,2 0 is keep alive, 1 means there are data, 2 means a type off error occured
    [1,2,3,4] size of the actual buffer I am sending
    [x(size of 1,2,3,4)] the actual 'Serialized' data buffer