C#: Trouble with socket ReceiveAsync and SendAsync on Remote Host

6.9k views Asked by At

First i want to say that this code with server/client works fine on my PC (both client and server running on the same PC)

Problem starts when i host the Server on dedicated server. The second time i try to Send or Receive with client, the client will take A LOT OF TIME to complete the operation (talking about receiving 1 byte of data that takes more then 1 hour !)

** I can avoid this problem by simply disconnecting and connecting the socket again after each Send/Receive command

I dont understand why it takes so many time if i will do more then 1 Send/Receive operation within the same connection session.


Here is an example:

to connect the server:

    RC_Server = new SocketConnection_Client(RC_IpEndPoint);

now client is connected to server, and i can start send / receive normally.

First time that i try to send or receive it works perfectly and fast (regardless of buffer length).

    RC_Server.sendCompleted = false;
    RC_Server.Send(buffer); //in this case buffer size is 1024
    while (!RC_Server.sendCompleted) { } //here thread is waiting for the send to complete

now, if i want to start a Receive session with server

        RC_Server.receiveCompleted = false;
        RC_Server.Receive(buffer.Length); //in this case byffer needs to get 4 bytes from server
        while (!RC_Server.receiveCompleted) { } // <<- Here it will take VERY long time for the operation to complete
        buffer = RC_Server.buffer;

The second Receive operation never get to the socket_receiveCompleted_Completed event.


But.. if i will close the connection with server after the first Send/Receive session, and then open a new connection with server and then do the next Send/Receive session, then everything would work perfectly. (and duplicate this method multiple times for multiple Send/Receive)

And again, the problem does not occur in my workstation (if i run server and client in same PC). it Only happens if i host the server on a remote host.

Here is part of my Socket Class:

    class SocketConnection_Client
    {
        public string errorMsg = string.Empty;
        public bool receiveCompleted = false;
        public bool sendCompleted = false;
        int bytesReceived = 0;
        public byte[] buffer;
        Socket socket;

        public SocketConnection_Client(IPEndPoint ipEP)
        {
            socket = new Socket(ipEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            try
            {
                socket.Connect(ipEP);
            }
            catch (Exception ex)
            {
                errorMsg = ex.Message;
                socket.Dispose();
                socket = null;
            }
        }

        public void Send(byte[] sBuffer)
        {
            buffer = null;
            if (socket == null)
            {
                sendCompleted = true;
                return;
            }
            sendCompleted = false;

            SocketAsyncEventArgs socket_sendCompleted = new SocketAsyncEventArgs();
            socket_sendCompleted.SetBuffer(sBuffer, 0, sBuffer.Length);
            socket_sendCompleted.Completed += socket_sendCompleted_Completed;
            socket.SendAsync(socket_sendCompleted);
        }

        void socket_sendCompleted_Completed(object sender, SocketAsyncEventArgs e)
        {
            sendCompleted = true;
        }

        public void Receive(int bLength)
        {
            bytesReceived = 0;
            buffer = null;
            if (socket == null)
            {
                receiveCompleted = true;
                return;
            }
            receiveCompleted = false;

            buffer = new byte[bLength];
            SocketAsyncEventArgs socket_receiveCompleted = new SocketAsyncEventArgs();
            socket_receiveCompleted.SetBuffer(buffer, 0, buffer.Length);
            socket_receiveCompleted.Completed += socket_receiveCompleted_Completed;
            socket.ReceiveAsync(socket_receiveCompleted);
        }

        private void Receive_Continue()
        {
            SocketAsyncEventArgs socket_receiveCompleted = new SocketAsyncEventArgs();
            socket_receiveCompleted.SetBuffer(buffer, bytesReceived, buffer.Length - bytesReceived);
            socket_receiveCompleted.Completed += socket_receiveCompleted_Completed;
            socket.ReceiveAsync(socket_receiveCompleted);
        }

        void socket_receiveCompleted_Completed(object sender, SocketAsyncEventArgs e)
        {
            bytesReceived += e.BytesTransferred;
            if (e.BytesTransferred == 0 && bytesReceived == 0)
            {
                socket.Dispose();
                socket = null;
                receiveCompleted = true;
                throw new Exception("Server Disconnected");
            }
            else if (bytesReceived != buffer.Length)
                Receive_Continue();
            else
                receiveCompleted = true;
        }
    }

Appreciated. Thanks.

1

There are 1 answers

0
Ben Voigt On BEST ANSWER

You're ignoring the return value from ReceiveAsync. Pay attention to the documentation -- there are two possible behaviors and you must check the return value to distinguish them:

Returns true if the I/O operation is pending. The SocketAsyncEventArgs.Completed event on the e parameter will be raised upon completion of the operation.

Returns false if the I/O operation completed synchronously. In this case, the SocketAsyncEventArgs.Completed event on the e parameter will not be raised and the e object passed as a parameter may be examined immediately after the method call returns to retrieve the result of the operation.