SocketAsyncEventArgs是.net提供的关于异步socket类,封装了IOCP的使用,可以用它方便的实现NIO(non-blocking IO)
NIO对于提升某些场景下Server性能和吞吐量有很大益处,准备在服务框架中使用它来编写简易rpc的部分
微软官方的demo代理有所缺少:
http://msdn.microsoft.com/en-us/library/system.net.sockets.socketasynceventargs.aspx
还有篇老外写的补充了缺少的代码:
http://www.codeproject.com/KB/IP/socketasynceventargssampl.aspx
不过例子还是感觉复杂了点,我只是需要知道SocketAsyncEventArgs本身如何使用而已,于是自行简化了一下:
using System; using System.Net; using System.Net.Sockets; using System.Text; namespace SocketAsyncServer { public static class Program { public static void Main(String[] args) { IPAddress[] addressList = Dns.GetHostEntry(Environment.MachineName).AddressList; new TcpListener().Listen(new IPEndPoint(addressList[addressList.Length - 1], 9900)); Console.ReadKey(); } } public class TcpListener { private SocketAsyncEventArgs Args; private Socket ListenerSocket; private StringBuilder buffers; public TcpListener() { } public void Listen(EndPoint e) { //buffer buffers = new StringBuilder(); //socket ListenerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); ListenerSocket.Bind(e); ListenerSocket.Listen(10); //异步socket事件 Args = new SocketAsyncEventArgs(); Args.Completed += new EventHandler<SocketAsyncEventArgs>(ProcessAccept); BeginAccept(Args); Console.WriteLine("server run at {0}", e.ToString()); } //开始接受 void BeginAccept(SocketAsyncEventArgs e) { e.AcceptSocket = null; if (!ListenerSocket.AcceptAsync(e)) ProcessAccept(ListenerSocket, e); } //接受完毕 开始接收和发送 void ProcessAccept(object sender, SocketAsyncEventArgs e) { Socket s = e.AcceptSocket; e.AcceptSocket = null; int bufferSize = 10;//1000 * 1024; var args = new SocketAsyncEventArgs(); args.Completed += new EventHandler<SocketAsyncEventArgs>(OnIOCompleted); args.SetBuffer(new byte[bufferSize], 0, bufferSize); args.AcceptSocket = s; if (!s.ReceiveAsync(args)) this.ProcessReceive(args); BeginAccept(e); } //IOCP回调 void OnIOCompleted(object sender, SocketAsyncEventArgs e) { switch (e.LastOperation) { case SocketAsyncOperation.Receive: this.ProcessReceive(e); break; case SocketAsyncOperation.Send: this.ProcessSend(e); break; default: throw new ArgumentException("The last operation completed on the socket was not a receive or send"); } } //接收完毕 void ProcessReceive(SocketAsyncEventArgs e) { if (e.BytesTransferred > 0) { if (e.SocketError == SocketError.Success) { //读取 var data=Encoding.ASCII.GetString(e.Buffer, e.Offset, e.BytesTransferred); buffers.Append(data); Console.WriteLine("Received:{0}", data); if (e.AcceptSocket.Available == 0) { //读取完毕 Console.WriteLine("Receive Complete.Data:{0}", buffers.ToString()); //重置 buffers = new StringBuilder(); //发送反馈 Byte[] sendBuffer = Encoding.ASCII.GetBytes("result from server"); e.SetBuffer(sendBuffer, 0, sendBuffer.Length); if (!e.AcceptSocket.SendAsync(e)) { this.ProcessSend(e); } } else if (!e.AcceptSocket.ReceiveAsync(e)) { this.ProcessReceive(e); } } else { //this.ProcessError(e); } } else { //this.CloseClientSocket(e); } } //发送完毕 void ProcessSend(SocketAsyncEventArgs e) { if (e.SocketError == SocketError.Success) { if (!e.AcceptSocket.ReceiveAsync(e)) { this.ProcessReceive(e); } } else { } } } }
上述代码run起来之后,打开cmd用telnet测试下即可
telnet 127.0.0.1 9900
顺便推荐一下园子兄弟写的一个框架实现了nio的rpc
http://www.cnblogs.com/overred/archive/2009/12/20/Shuttler_Net_2.html