C# 异步套接字错误

C# 异步套接字错误,c#,asyncsocket,C#,Asyncsocket,我试着做一些小的改变 我想从这个“echo服务器”示例中创建“聊天服务器” 所以 我在类服务器中添加了一些块,这很好,但是。。。就在两个telnet连接之间,当我添加两个以上的客户端时,我得到错误“使用此SocketAsyncEventArgs实例的异步套接字操作已经在进行中。” 你能告诉我错误在哪里吗? 非常感谢 这是我的服务器类: namespace AsyncSocketSample { /// <summary> /// Implements the conn

我试着做一些小的改变 我想从这个“echo服务器”示例中创建“聊天服务器”

所以

我在类服务器中添加了一些块,这很好,但是。。。就在两个telnet连接之间,当我添加两个以上的客户端时,我得到错误“使用此SocketAsyncEventArgs实例的异步套接字操作已经在进行中。”

你能告诉我错误在哪里吗? 非常感谢

这是我的服务器类:

namespace AsyncSocketSample
{
    /// <summary>
    /// Implements the connection logic for the socket server.  After accepting a connection, all data read
    /// from the client is sent back to the client.  The read and echo back to the client pattern is continued 
    /// until the client disconnects.
    /// </summary>
    class Server
    {
        private int m_numConnections;   // the maximum number of connections the sample is designed to handle simultaneously 
        private int m_receiveBufferSize;// buffer size to use for each socket I/O operation 
        BufferManager m_bufferManager;  // represents a large reusable set of buffers for all socket operations
        const int opsToPreAlloc = 2;    // read, write (don't alloc buffer space for accepts)
        Socket listenSocket;            // the socket used to listen for incoming connection requests
        // pool of reusable SocketAsyncEventArgs objects for write, read and accept socket operations
        SocketAsyncEventArgsPool m_readWritePool;
        int m_totalBytesRead;           // counter of the total # bytes received by the server
        int m_numConnectedSockets;      // the total number of clients connected to the server 
        Semaphore m_maxNumberAcceptedClients;

        //The ClientInfo structure holds the required information about every
        //client connected to the server
        struct ClientInfo
        {
            public Socket socket;   //Socket of the client
            public AsyncUserToken token; // User Token
            //public string strName;  //Name by which the user logged into the chat room
        }

        //The collection of all clients logged into the room (an array of type ClientInfo)
        ArrayList clientList = new ArrayList();

        /// <summary>
        /// Create an uninitialized server instance.  To start the server listening for connection requests
        /// call the Init method followed by Start method 
        /// </summary>
        /// <param name="numConnections">the maximum number of connections the sample is designed to handle simultaneously</param>
        /// <param name="receiveBufferSize">buffer size to use for each socket I/O operation</param>
        public Server(int numConnections, int receiveBufferSize)
        {
            m_totalBytesRead = 0;
            m_numConnectedSockets = 0;
            m_numConnections = numConnections;
            m_receiveBufferSize = receiveBufferSize;
            // allocate buffers such that the maximum number of sockets can have one outstanding read and 
            //write posted to the socket simultaneously  
            m_bufferManager = new BufferManager(receiveBufferSize * numConnections * opsToPreAlloc,
                receiveBufferSize);

            m_readWritePool = new SocketAsyncEventArgsPool(numConnections);
            m_maxNumberAcceptedClients = new Semaphore(numConnections, numConnections); 
        }

        /// <summary>
        /// Initializes the server by preallocating reusable buffers and context objects.  These objects do not 
        /// need to be preallocated or reused, by is done this way to illustrate how the API can easily be used
        /// to create reusable objects to increase server performance.
        /// </summary>
        public void Init()
        {
            // Allocates one large byte buffer which all I/O operations use a piece of.  This gaurds 
            // against memory fragmentation
            m_bufferManager.InitBuffer();

            // preallocate pool of SocketAsyncEventArgs objects
            SocketAsyncEventArgs readWriteEventArg;

            for (int i = 0; i < m_numConnections; i++)
            {
                //Pre-allocate a set of reusable SocketAsyncEventArgs
                readWriteEventArg = new SocketAsyncEventArgs();
                readWriteEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed);
                readWriteEventArg.UserToken = new AsyncUserToken();

                // assign a byte buffer from the buffer pool to the SocketAsyncEventArg object
                m_bufferManager.SetBuffer(readWriteEventArg);

                // add SocketAsyncEventArg to the pool
                m_readWritePool.Push(readWriteEventArg);
            }

        }

        /// <summary>
        /// Starts the server such that it is listening for incoming connection requests.    
        /// </summary>
        /// <param name="localEndPoint">The endpoint which the server will listening for conenction requests on</param>
        public void Start(IPEndPoint localEndPoint)
        {
            // create the socket which listens for incoming connections
            listenSocket = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            listenSocket.Bind(localEndPoint);
            // start the server with a listen backlog of 100 connections
            listenSocket.Listen(100);

            // post accepts on the listening socket
            StartAccept(null);            

            //Console.WriteLine("{0} connected sockets with one outstanding receive posted to each....press any key", m_outstandingReadCount);
            Console.WriteLine("Press any key to terminate the server process....");
            Console.ReadKey();
        }


        /// <summary>
        /// Begins an operation to accept a connection request from the client 
        /// </summary>
        /// <param name="acceptEventArg">The context object to use when issuing the accept operation on the 
        /// server's listening socket</param>
        public void StartAccept(SocketAsyncEventArgs acceptEventArg)
        {
            if (acceptEventArg == null)
            {
                acceptEventArg = new SocketAsyncEventArgs();
                acceptEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(AcceptEventArg_Completed);
            }
            else
            {
                // socket must be cleared since the context object is being reused
                acceptEventArg.AcceptSocket = null;
            }

            m_maxNumberAcceptedClients.WaitOne();
            bool willRaiseEvent = listenSocket.AcceptAsync(acceptEventArg);
            if (!willRaiseEvent)
            {
                ProcessAccept(acceptEventArg);
            }
        }

        /// <summary>
        /// This method is the callback method associated with Socket.AcceptAsync operations and is invoked
        /// when an accept operation is complete
        /// </summary>
        void AcceptEventArg_Completed(object sender, SocketAsyncEventArgs e)
        {
            ProcessAccept(e);
        }

        private void ProcessAccept(SocketAsyncEventArgs e)
        {
            Interlocked.Increment(ref m_numConnectedSockets);
            Console.WriteLine("Client connection accepted. There are {0} clients connected to the server",
                m_numConnectedSockets);

            // Get the socket for the accepted client connection and put it into the 
            //ReadEventArg object user token
            SocketAsyncEventArgs readEventArgs = m_readWritePool.Pop();
            ((AsyncUserToken)readEventArgs.UserToken).Socket = e.AcceptSocket;

            // As soon as the client is connected, post a receive to the connection
            bool willRaiseEvent = e.AcceptSocket.ReceiveAsync(readEventArgs);
            if(!willRaiseEvent){
                ProcessReceive(readEventArgs);
            }

            ClientInfo clientInfo = new ClientInfo();
            clientInfo.socket = ((AsyncUserToken)readEventArgs.UserToken).Socket;
            clientInfo.token =  (AsyncUserToken)readEventArgs.UserToken;
            clientList.Add(clientInfo);

            // Accept the next connection request
            StartAccept(e);
        }

        /// <summary>
        /// This method is called whenever a receive or send opreation is completed on a socket 
        /// </summary> 
        /// <param name="e">SocketAsyncEventArg associated with the completed receive operation</param>
        void IO_Completed(object sender, SocketAsyncEventArgs e)
        {
            // determine which type of operation just completed and call the associated handler
            switch (e.LastOperation)
            {
                case SocketAsyncOperation.Receive:
                    ProcessReceive(e);
                    break;
                case SocketAsyncOperation.Send:
                    ProcessSend(e);
                    break;
                default:
                    throw new ArgumentException("The last operation completed on the socket was not a receive or send");
            }       

        }

        /// <summary>
        /// This method is invoked when an asycnhronous receive operation completes. If the 
        /// remote host closed the connection, then the socket is closed.  If data was received then
        /// the data is echoed back to the client.
        /// </summary>
        private void ProcessReceive(SocketAsyncEventArgs e)
        {
            // check if the remote host closed the connection
            AsyncUserToken token = (AsyncUserToken)e.UserToken;
            if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
            {
                //increment the count of the total bytes receive by the server
                Interlocked.Add(ref m_totalBytesRead, e.BytesTransferred);
                Console.WriteLine("The server has read a total of {0} bytes", m_totalBytesRead);
                ///////////////////////////////////////////////////////////////////////////////////////////////////


                try
                {
                    foreach (ClientInfo clientInfo in clientList)
                    {
                        if (clientInfo.token != token)
                        {                           
                            //Data received send to the all client but not for sender
                            bool willRaiseEvent = clientInfo.token.Socket.SendAsync(e); // token.Socket.SendAsync(e);
                            if (!willRaiseEvent)
                            {
                                ProcessSend(e);
                            }
                        }
                    }
                }
                catch (Exception x)
                {
                    Console.WriteLine(x.Message.ToString());
                    Console.ReadKey();
                }
                ///////////////////////////////////////////////////////////////////////////////////////////////////


            }
            else
            {
                CloseClientSocket(e);
            }
        }

        /// <summary>
        /// This method is invoked when an asynchronous send operation completes.  The method issues another receive
        /// on the socket to read any additional data sent from the client
        /// </summary>
        /// <param name="e"></param>
        private void ProcessSend(SocketAsyncEventArgs e)
        {
            if (e.SocketError == SocketError.Success)
            {
                // done echoing data back to the client
                AsyncUserToken token = (AsyncUserToken)e.UserToken;
                // read the next block of data send from the client
                bool willRaiseEvent = token.Socket.ReceiveAsync(e);
                if (!willRaiseEvent)
                {
                    ProcessReceive(e);
                }
            }
            else
            {
                CloseClientSocket(e);
            }
        }

        private void CloseClientSocket(SocketAsyncEventArgs e)
        {
            AsyncUserToken token = e.UserToken as AsyncUserToken;

            // close the socket associated with the client
            try
            {
                token.Socket.Shutdown(SocketShutdown.Send);
            }
            // throws if client process has already closed
            catch (Exception) { }
            token.Socket.Close();
            ///////////////////////////////////////////
            // Connection is terminated, either by force or
            // willingly
            int nIndex = 0;
            foreach (ClientInfo client in clientList)
            {
                if (client.token == token)
                {
                    clientList.RemoveAt(nIndex);
                    break;
                }
                ++nIndex;
            }
            ///////////////////////////////////////////
            // decrement the counter keeping track of the total number of clients connected to the server
            Interlocked.Decrement(ref m_numConnectedSockets);
            m_maxNumberAcceptedClients.Release();
            Console.WriteLine("A client has been disconnected from the server. There are {0} clients connected to the server", m_numConnectedSockets);

            // Free the SocketAsyncEventArg so they can be reused by another client
            m_readWritePool.Push(e);
        }

    }
名称空间AsyncSocketSample
{
/// 
///实现套接字服务器的连接逻辑。接受连接后,将读取所有数据
///从客户端发送回客户端。继续读取和回显到客户端模式
///直到客户端断开连接。
/// 
类服务器
{
private int m_numConnections;//样本设计为同时处理的最大连接数
private int m_receiveBufferSize;//用于每个套接字I/O操作的缓冲区大小
BufferManager m_BufferManager;//表示用于所有套接字操作的大型可重用缓冲区集
const int opsToPreAlloc=2;//读取、写入(不为接受分配缓冲区空间)
Socket listenSocket;//用于侦听传入连接请求的套接字
//用于写入、读取和接受套接字操作的可重用SocketAsyncEventArgs对象池
SocketAsyncEventArgsPool m_readWritePool;
int m_totalBytesRead;//服务器接收的总字节数的计数器
int m_numConnectedSockets;//连接到服务器的客户端总数
信号量m_MaxNumberAcceptedClient;
//ClientInfo结构保存有关每个
//连接到服务器的客户端
结构ClientInfo
{
公共套接字;//客户端的套接字
公共异步用户令牌;//用户令牌
//public string strName;//用户登录聊天室时使用的名称
}
//登录到文件室的所有客户端的集合(ClientInfo类型的数组)
ArrayList clientList=新的ArrayList();
/// 
///创建未初始化的服务器实例。若要启动服务器侦听连接请求
///调用Init方法,后跟Start方法
/// 
///样本设计为同时处理的最大连接数
///用于每个套接字I/O操作的缓冲区大小
公共服务器(int numConnections、int receiveBufferSize)
{
m_totalBytesRead=0;
m_numConnectedSockets=0;
m_numConnections=numConnections;
m_receiveBufferSize=receiveBufferSize;
//分配缓冲区,以便最大数量的套接字可以有一个未完成的读和写操作
//同时向套接字发送写操作
m_bufferManager=新的bufferManager(receiveBufferSize*numConnections*opsToPreAlloc,
接收缓冲区大小);
m_readWritePool=新的SocketAsyncEventArgsPool(numConnections);
m_MaxNumberAcceptedClient=新信号量(numConnections,numConnections);
}
/// 
///通过预分配可重用缓冲区和上下文对象来初始化服务器。这些对象不会
///需要预先分配或重用,通过这种方式来说明如何轻松使用API
///创建可重用对象以提高服务器性能。
/// 
公共void Init()
{
//分配一个所有I/O操作都使用的大字节缓冲区。此
//防止内存碎片
m_bufferManager.InitBuffer();
//预分配SocketAsyncEventArgs对象池
SocketAsyncEventArgs readWriteEventArg;
对于(int i=0;iforeach (ClientInfo clientInfo in clientList)
{
    if (clientInfo.token != token)
    {                           
        //Data received send to the all client but not for sender
        bool willRaiseEvent = clientInfo.token.Socket.SendAsync(e); // token.Socket.SendAsync(e);
        if (!willRaiseEvent)
        {
            ProcessSend(e);
        }
    }
}