异步I/O模型
异步I/O模型
异步I/O模型是.NET中最高效的I/O模型,因为在Windows NT 4和以上的系统中.NET异步I/O在内部使用了I/O完成端口(I/O completion port,以下简称IOCP)。了解WinSock2的朋友应该知道,IOCP是Windows平台上系统性能和伸缩性最好的I/O模型。然而在WinSock2平台上直接使用IOCP也是相当的繁琐,Jeffrey Richter在Advanced 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 阅读(4880) 评论(17) 编辑 收藏 举报