TCP服务器复位AcceptSocket.在SocketAsyncEventArgs实例上进行ReceiveAsync操

本文关键字:ReceiveAsync 实例 SocketAsyncEventArgs 服务器 复位 AcceptSocket TCP | 更新日期: 2023-09-27 18:04:15

我目前有一个使用c# SAEA实现的TCP服务器。我想做的是在连接到服务器的2个TCP客户端(客户端1客户端2)之间转发消息。

  • 服务器使用receiveSendEventArgs.AcceptSocket。ReceiveAsync receiveSendEventArgs.AcceptSocket。SendAsync命令发送和从每个连接的客户端接收信息问题。
  • 服务器在receiveSendEventArgs.AcceptSocket中。Client 1Client 2的ReceiveAsync操作。
  • 客户端1发送一条消息,服务器接受该消息。服务器看到客户端2也已连接,因此需要获取receiveSendEventArgs客户端2的引用来转发消息。

然而,服务器接受客户端2receiveSendEventArgs的引用,并开始准备缓冲区(SetBuffer)来发送消息,我相信因为套接字仍然处于客户端2的"ReceiveSync"状态,它爆发了以下消息:

"使用SocketAsyncEventArgs实例,异步套接字操作已经在进行中。 "

是否有办法切换客户端2状态在服务器上从"ReceiveAsync"到"SendAsync",这样当我尝试SendData到客户端2时不会出错?我知道当发送或接收操作完成时触发Completed事件,但是,直接调用我的IO_Completed方法不会改变操作。

在for循环中为SocketAsyncEventArgs的完成事件设置eventandler:eventArgObjectForPool。Completed += new EventHandler(IO_Completed);

void IO_Completed(object sender, 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){

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

TCP服务器复位AcceptSocket.在SocketAsyncEventArgs实例上进行ReceiveAsync操

这不是我想要做的,但我可以调用以下代码:

receiveSendEventArgs.AcceptSocket.Write (strMyBuffer);

这允许我写入相同的套接字,我没有任何错误。我想坚持使用异步命令,但屈服于同步写入,它没有影响我的服务器。也许还有其他解决办法。