С#: проблема с сокетом ReceiveAsync и SendAsync на удаленном хосте

Во-первых, я хочу сказать, что этот код с сервером/клиентом отлично работает на моем ПК (и клиент, и сервер работают на одном ПК).

Проблема начинается, когда я размещаю сервер на выделенном сервере. Во второй раз, когда я пытаюсь отправить или получить с помощью клиента, клиенту потребуется МНОГО ВРЕМЕНИ для завершения операции (речь идет о получении 1 байта данных, который занимает более 1 часа!)

** Я могу избежать этой проблемы, просто отключая и снова подключая сокет после каждой команды отправки/получения.

Я не понимаю, почему это занимает так много времени, если я буду выполнять более 1 операции отправки/получения в рамках одного и того же сеанса подключения.


Вот пример:

для подключения сервера:

    RC_Server = new SocketConnection_Client(RC_IpEndPoint);

теперь клиент подключен к серверу, и я могу нормально отправлять/получать.

В первый раз, когда я пытаюсь отправить или получить, он работает отлично и быстро (независимо от длины буфера).

    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

теперь, если я хочу начать сеанс приема с сервером

        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;

Вторая операция получения никогда не достигает события socket_receiveCompleted_Completed.


Но... если я закрою соединение с сервером после первого сеанса отправки/получения, а затем открою новое соединение с сервером, а затем выполню следующий сеанс отправки/получения, тогда все будет работать отлично. (и дублировать этот метод несколько раз для нескольких отправок/получений)

И снова проблема не возникает на моей рабочей станции (если я запускаю сервер и клиент на одном ПК). Это происходит только в том случае, если я размещаю сервер на удаленном хосте.

Вот часть моего класса сокетов:

    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;
        }
    }

Ценится. Спасибо.


person Daniel Raban    schedule 22.08.2013    source источник


Ответы (1)


Вы игнорируете возвращаемое значение из ReceiveAsync. Обратите внимание на документация -- есть два возможных поведения, и вы должны проверить возвращаемое значение, чтобы различать их:

Возвращает true, если ожидается операция ввода-вывода. Событие SocketAsyncEventArgs.Completed для параметра e будет вызвано после завершения операции.

Возвращает false, если операция ввода-вывода завершена синхронно. В этом случае событие SocketAsyncEventArgs.Completed для параметра e не будет вызвано, а объект e, переданный в качестве параметра, может быть проверен сразу после события вызов метода возвращается для получения результата операции.

person Ben Voigt    schedule 28.03.2016