NCindy

.net平台上的高性能网络程序开发框架

异步I/O模型

异步I/O模型

异步I/O模型是.NET中最高效的I/O模型,因为在Windows NT 4和以上的系统中.NET异步I/O在内部使用了I/O完成端口(I/O completion port,以下简称IOCP)。了解WinSock2的朋友应该知道,IOCPWindows平台上系统性能和伸缩性最好的I/O模型。然而在WinSock2平台上直接使用IOCP也是相当的繁琐,Jeffrey RichterAdvanced Windows中曾经认为IOCP是最复杂的Windows内核对象,但是在.NET平台的帮助下,我们只需要使用异步的Socket方法就可以享受到IOCP带来的优越性能了。

IOCP的基本原理也很简单:应用程序向Windows内核投递一些异步请求,当内核完成这些请求的时候,把这些请求的结果放入IOCP的队列中,在IOCP上等待的线程池会立即处理这些完成的结果。

异步I/O模型使用起来也很简单,甚至比选择I/O模型还要简单,你不需要为Select准备列表,不需要担心连接数超出了Select的限制。你要做的就是调用BeginXXX方法,并且编写一个合适的回调方法,等待I/O操作完成之后被调用。

下面我们就把选择IO模型中的那个例子改为异步I/O模型来处理。

 

using System;

using System.Net.Sockets;

using System.Net;

using System.IO;

using System.Collections;

 

namespace NCindy.Articles.Samples

{

    class AsyncIOSample

    {

        static void Main(string[] args)

        {

            EchoServer echoServer = new EchoServer();

            echoServer.Start();

 

            Console.WriteLine("Press 'Enter' to quit.");

            Console.ReadLine();

 

            echoServer.Stop();

        }

    }

 

    internal class AsyncState

    {

        public readonly byte[] buffer;

        public readonly Socket socket;

 

        public readonly int offset;

        public readonly int count;

 

        public AsyncState(byte[] buffer , Socket sock, int offset, int count)

        {

            this.socket = sock;

            this.buffer = buffer;

            this.offset = offset;

            this.count = count;

        }

    }

 

    internal class EchoServer

    {

        private readonly Socket listener;

        private readonly ArrayList clients = new ArrayList();

 

        private readonly AsyncCallback onAccepted;

 

        private readonly static AsyncCallback onReceived

            = new AsyncCallback(ClientEndReceive);

 

        private readonly static AsyncCallback onSent

            = new AsyncCallback(ClientEndSend);

 

        private static void ClientEndReceive(IAsyncResult asyncResult)

        {

            AsyncState ras = asyncResult.AsyncState as AsyncState;

           

            int recvSize = ras.socket.EndReceive(asyncResult);

 

            //如果接收到的数据长度为,则说明远端连接已经关闭

            if (recvSize == 0)

            {

                return;

            }

            //再投递一个接收请求

            PostReceive(ras.socket);

 

            //将收到的数据发送回去

            PostSend(ras.socket, ras.buffer, 0, recvSize);

        }

 

        private static void ClientEndSend(IAsyncResult asyncResult)

        {

            AsyncState state = asyncResult.AsyncState as AsyncState;

 

            Socket sock = state.socket;

 

            byte[] buffer = state.buffer;

           

            int sentBytes = sock.EndSend(asyncResult);

 

            int remainBytes = state.count - sentBytes;

           

            if(remainBytes <= 0)

            {

                return;

            }

 

            Console.WriteLine(

                string.Format("Buffer length: {0} Remain bytes: {1} Sent bytes: {2}" ,

                buffer.Length, remainBytes, sentBytes));

 

 

            PostSend(sock, buffer, buffer.Length - remainBytes, remainBytes);

        }

 

        private void ListenerEndAccept(IAsyncResult asynResult)

        {

            PostAccept();

            Socket sock = this.listener.EndAccept(asynResult);

 

            lock (this.clients.SyncRoot)

            {

                this.clients.Add(sock);

            }

 

            PostReceive(sock);

        }

 

        public EchoServer()

        {

            onAccepted = new AsyncCallback(ListenerEndAccept);

 

            listener = new Socket(AddressFamily.InterNetwork,

                SocketType.Stream,

                ProtocolType.Tcp);

        }

 

        private void PostAccept()

        {

            //投递一个Accept请求

            listener.BeginAccept(0, onAccepted, null);

        }

 

        public void Start()

        {

            listener.Bind(new IPEndPoint(IPAddress.Any, 7777));

 

            listener.Listen(200);

 

            for (int i = 0; i < 5; i++)

            {

                PostAccept();

            }

        }

 

        public static void PostReceive(Socket sock)

        {

            byte [] recvBuf = new byte[1024];

 

            sock.BeginReceive(recvBuf,

                0,

                recvBuf.Length,

                SocketFlags.None,

                onReceived,

                new AsyncState(recvBuf,

                sock , 0 , recvBuf.Length));

        }

 

        public static void PostSend(Socket sock, byte[] buffer, int offset, int count)

        {

            sock.BeginSend(buffer,

                offset,

                count,

                SocketFlags.None,

                onSent,

                new AsyncState(buffer, sock , offset , count));

        }

 

 

        public void Stop()

        {

            //关闭监听socket

            listener.Close();

 

            lock (this.clients.SyncRoot)

            {

                //关闭所有的客户端sockets

                foreach (Socket s in this.clients)

                {

                    s.Shutdown(SocketShutdown.Both);

                    s.Close();

                }

            }

        }

    }

}

posted on 2006-11-01 19:14  iceboundrock  阅读(4875)  评论(17编辑  收藏  举报

导航