利用IO完成端口实现高性能的UDP或TCP通信

来源:互联网 发布:一个月淘宝可以退货吗 编辑:程序博客网 时间:2024/06/05 00:27

多花点心思还是能查到的,终于在MSDN上找到了UDP的异步通信模型,并且更加巧妙的是,同时提供了基于TCP的IO完成端口模型,只是国内这块相关资料确实太少,基本查询不到。

不过老外的代码只是写了个大概,这已经提供很好的思路了,苦于卡在这个瓶颈上好久了,微软内部的说法是基于这个新的异步封送类的内存分配效率是相当高的。

与自己写的服务器端异步封送服务比较,整个异步封送的定义有很多一致点,这个是自己没想到的,但是自己写的异步封送类,由于是采用链表作为容器管理,效率会差很多。

但是这个类中也是有缺点的,可以将队列改为消息队列,这样整体的效率会更高。

技术有时只有到了绝路才会去查找另外一种方法,苦苦要处理的UDP服务层,因为一直没达到效果,按照原思路执行不下去了。

// 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.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;    // Create an uninitialized server instance.      // To start the server listening for connection requests    // call the Init method followed by Start method     //    // <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);     }    // Initializes the server by preallocating reusable buffers and     // context objects.  These objects do not need to be preallocated     // or reused, but it is done this way to illustrate how the API can     // easily be used to create reusable objects to increase server performance.    //    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);        }    }    // Starts the server such that it is listening for     // incoming connection requests.        //    // <param name="localEndPoint">The endpoint which the server will listening     // for connection 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();    }    // Begins an operation to accept a connection request from the client     //    // <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);        }    }    // This method is the callback method associated with Socket.AcceptAsync     // operations and is invoked when an accept operation is complete    //    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);        }        // Accept the next connection request        StartAccept(e);    }    // This method is called whenever a receive or send operation is completed on a socket     //    // <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");        }           }    // This method is invoked when an asynchronous 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.    //    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);            //echo the data received back to the client            e.SetBuffer(e.Offset, e.BytesTransferred);            bool willRaiseEvent = token.Socket.SendAsync(e);            if (!willRaiseEvent)            {                ProcessSend(e);            }        }        else        {            CloseClientSocket(e);        }    }    // 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    //    // <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();        // 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);    }}    


0 0