TCP-сервер сбрасывает операцию AcceptSocket.ReceiveAsync для экземпляра SocketAsyncEventArgs

В настоящее время у меня есть TCP-сервер, реализованный с использованием C # SAEA. Я бы хотел пересылать сообщение между двумя TCP-клиентами, подключенными к серверу (Клиент 1 и Клиент 2).

  • Сервер использует команды receiveSendEventArgs.AcceptSocket.ReceiveAsync и receiveSendEventArgs.AcceptSocket.SendAsync для беспроблемной отправки и получения информации от каждого из подключенных клиентов.
  • Сервер находится в операции receiveSendEventArgs.AcceptSocket.ReceiveAsync как для клиента 1, так и для клиента 2.
  • Клиент 1 отправляет одно сообщение, и сервер принимает сообщение. Сервер видит, что Клиент 2 также подключен, и поэтому ему необходимо получить ссылку receiveSendEventArgs на Клиент 2, чтобы переслать сообщение.

Однако Сервер принимает ссылку receiveSendEventArgs из Клиента 2 и начинает готовить буфер (SetBuffer) для отправки сообщения, и я считаю, поскольку Socket все еще находится в " ReceiveSync "для клиента 2, появляется следующее сообщение:

"Асинхронная операция сокета уже выполняется с использованием этого экземпляра SocketAsyncEventArgs."

Есть ли способ переключить состояние клиента 2 на сервере с «ReceiveAsync» на «SendAsync», чтобы не возникала ошибка, когда я пытаюсь отправить данные на клиент 2 ? Я знаю, что событие Завершено запускается при завершении операций отправки или получения, однако простой вызов моего метода IO_Completed напрямую не изменяет операцию.

В цикле for настройка обработчиков событий для событий Completed для SocketAsyncEventArgs: eventArgObjectForPool.Completed + = new EventHandler (IO_Completed);

void IO_Completed (объект-отправитель, SocketAsyncEventArgs e) {

        DataHoldingUserToken receiveSendToken = (DataHoldingUserToken)e.UserToken;
        //More business logic here ...
        // determine which type of operation just completed and call the associated handler
        switch (e.LastOperation)
        {
            case SocketAsyncOperation.Receive:
                if (Program.watchProgramFlow == true)   //for testing
                {
                    Program.testWriter.WriteLine("IO_Completed method in Receive, receiveSendToken id " + receiveSendToken.TokenId);
                }                    
                ProcessReceive(e);
                break;

            case SocketAsyncOperation.Send:
                if (Program.watchProgramFlow == true)   //for testing
                {
                    Program.testWriter.WriteLine("IO_Completed method in Send, id " + receiveSendToken.TokenId);
                }

                ProcessSend(e);
                break;

            default:
                //This exception will occur if you code the Completed event of some
                //operation to come to this method, by mistake.
                throw new ArgumentException("The last operation completed on the socket was not a receive or send");
        }
    }

private void StartReceive (SocketAsyncEventArgs receiveSendEventArgs) {

        DataHoldingUserToken receiveSendToken = (DataHoldingUserToken)receiveSendEventArgs.UserToken;

        if (Program.watchProgramFlow == true)   //for testing
        {                
            Program.testWriter.WriteLine("StartReceive(), receiveSendToken id " + receiveSendToken.TokenId);
        }

        switch (receiveSendToken.clientInfo.currentState)
        {
            case MyClient.ClientState.Connecting://This occurs when we get client to connect for first time. However, it will automatically disconnect

                receiveSendToken.theMediator.HandleData(receiveSendToken.theDataHolder);

                // Create a new DataHolder for next message.
                receiveSendToken.CreateNewDataHolder();

                //Reset the variables in the UserToken, to be ready for the
                //next message that will be received on the socket in this
                //SAEA object.
                receiveSendToken.Reset(true);

                receiveSendToken.theMediator.PrepareOutgoingData();
                StartSend(receiveSendToken.theMediator.GiveBack());

                //******************************************************************
                break;

            default:
                //Set the buffer for the receive operation.
                receiveSendEventArgs.SetBuffer(receiveSendToken.bufferOffsetReceive, this.socketListenerSettings.BufferSize);                    

                // Post async receive operation on the socket.
                bool willRaiseEvent = receiveSendEventArgs.AcceptSocket.ReceiveAsync(receiveSendEventArgs);

                //Socket.ReceiveAsync 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. So, true will cause the IO_Completed
                //method to be called when the receive operation completes. 
                //That's because of the event handler we created when building
                //the pool of SocketAsyncEventArgs objects that perform receive/send.
                //It was the line that said
                //eventArgObjectForPool.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed);

                //Socket.ReceiveAsync returns false if I/O operation completed synchronously. 
                //In that case, the SocketAsyncEventArgs.Completed event on the e parameter 

                if (!willRaiseEvent)
                {
                    if (Program.watchProgramFlow == true)   //for testing
                    {
                        Program.testWriter.WriteLine("StartReceive in if (!willRaiseEvent), receiveSendToken id " + receiveSendToken.TokenId);
                    }

                    ProcessReceive(receiveSendEventArgs);
                }
                break;
        }
    }

private void StartSend (SocketAsyncEventArgs receiveSendEventArgs) {DataHoldingUserToken receiveSendToken = (DataHoldingUserToken) receiveSendEventArgs.UserToken;

        if (Program.watchProgramFlow == true)   //for testing
        {
            Program.testWriter.WriteLine("StartSend, id " + receiveSendToken.TokenId);
        }
        if (Program.watchThreads == true)   //for testing
        {
            DealWithThreadsForTesting("StartSend()", receiveSendToken);
        }

        if (receiveSendToken.sendBytesRemainingCount <= this.socketListenerSettings.BufferSize)
        {
            Program.testWriter.WriteLine("blocking:?(" + receiveSendEventArgs.AcceptSocket.Blocking + ")");
            receiveSendEventArgs.SetBuffer(receiveSendToken.bufferOffsetSend, receiveSendToken.sendBytesRemainingCount);
            //Copy the bytes to the buffer associated with this SAEA object.
            Buffer.BlockCopy(receiveSendToken.dataToSend, receiveSendToken.bytesSentAlreadyCount, receiveSendEventArgs.Buffer, receiveSendToken.bufferOffsetSend, receiveSendToken.sendBytesRemainingCount);
        }
        else
        {
            //We cannot try to set the buffer any larger than its size.
            //So since receiveSendToken.sendBytesRemainingCount > BufferSize, we just
            //set it to the maximum size, to send the most data possible.
            receiveSendEventArgs.SetBuffer(receiveSendToken.bufferOffsetSend, this.socketListenerSettings.BufferSize);
            //Copy the bytes to the buffer associated with this SAEA object.
            Buffer.BlockCopy(receiveSendToken.dataToSend, receiveSendToken.bytesSentAlreadyCount, receiveSendEventArgs.Buffer, receiveSendToken.bufferOffsetSend, this.socketListenerSettings.BufferSize);

            //We'll change the value of sendUserToken.sendBytesRemainingCount
            //in the ProcessSend method.
        }

        //post asynchronous send operation
        bool willRaiseEvent = receiveSendEventArgs.AcceptSocket.SendAsync(receiveSendEventArgs);

        if (!willRaiseEvent)
        {
            if (Program.watchProgramFlow == true)   //for testing
            {
                Program.testWriter.WriteLine("StartSend in if (!willRaiseEvent), receiveSendToken id " + receiveSendToken.TokenId);
            }

            ProcessSend(receiveSendEventArgs);
        }            
    }

person Miles    schedule 23.07.2015    source источник
comment
Не могли бы вы немного лучше отформатировать свой вопрос и, возможно, предоставить образец кода и любые ошибки / журналы, которые вы получаете?   -  person Kalel Wade    schedule 23.07.2015
comment
Обновление форматирования, которое вы сделали, приятно, но не так важно, как добавление минимального, полного и проверяемого примера вашего кода.   -  person Scott Chamberlain    schedule 23.07.2015


Ответы (1)


Это было не то, что я хотел сделать, но я смог назвать следующее:

receiveSendEventArgs.AcceptSocket.Write (strMyBuffer);

Это позволило мне писать в тот же сокет, и у меня не было никаких ошибок. Я хотел придерживаться асинхронных команд, но уступил синхронной записи, и это не повлияло на мой сервер. Возможно, есть другие решения.

person Miles    schedule 29.07.2015
comment
Вероятно, вам в любом случае не нужен асинхронный ввод-вывод, поэтому это решение, вероятно, подойдет. В любом случае SAEA - устаревший API. Используйте сокеты с ожиданием. Если все, что вы хотите сделать, это пересылать данные, тогда все, что вам нужно, это два NetworkStreams и один вызов CopyTo (Async). - person usr; 30.07.2015