阅读目录:缓存
上篇提到用多线程处理多个阻塞同步IO而实现并发服务端,这种模式在链接数量比较小的时候很是适合,一旦链接过多,性能会急速降低。 在大多数服务端网络软件中会采用一种异步IO的方式来提升性能。网络
采用异步IO方式,意味着单线程能够处理多个请求了,链接发起一个Receive请求后,当前线程能够当即去作别的事情,当数据接收完毕通知线程处理便可。
其数据接收分2部分:多线程
第二部分示例代码:并发
byte[] msg = new byte[256]; socket.Receive(msg);
介绍这2部分的目的是方便区分其余几种方式。 对于用户程序来讲,同步IO和异步IO的区别在于第二部分是否须要等待。异步
非阻塞式同步IO,由同步IO延伸出来,把这个名词拆分红2部分描述:socket
既然是第一部分是非阻塞的,那就须要一种方法得知何时内核缓冲区是OK的。 设置非阻塞模式后,在链接调用Receive方法时,会当即返回一个标记,告知用户程序内核缓存区有没有数据,若是有数据开始进行第二部分操做,从内核缓冲区拷贝到用户程序缓冲区。 因为系统会返回个标记,那能够经过轮询方式来判断内核缓冲区是否OK。函数
设置非阻塞模式参考代码:性能
SocketInformation sif=new SocketInformation(); sif.Options=SocketInformationOptions.NonBlocking; sif.ProtocolInformation = new byte[24]; Socket socket = new Socket(sif);
轮询参考代码:spa
while(true) { byte[] msg = new byte[256]; var temp = socket.Receive(msg); if (temp=="OK"){ //do something }else{ continue } }
这种方式近乎淘汰了,了解便可。线程
上面介绍过:
当回调到执行时,数据已经在用户程序缓冲区已经准备好了,在回调代码中对这部分数据进行相应的逻辑便可。
发出接收请求:
static byte[] msg = new byte[256]; var temp = socket.BeginReceive(msg, 0, msg.Length, 0, new AsyncCallback(ReadCallback), socket);
回调函数中对数据作处理:
public static void ReadCallback(IAsyncResult ar) { var socket = (Socket)ar.AsyncState; int read = socket.EndReceive(ar); DoSomething(msg); socket.BeginReceive(msg, 0, msg.Length, 0, new AsyncCallback(Read_Callback), socket); }
当回调函数执行时,表示数据已经准备好,须要先结束接收请求EndReceive,以便第二次发出接收请求。 在服务端程序中要处理多个客户端的接收,再次发出BeginReceive接收数据请求便可。
这里的回调函数是在另一个线程的触发,必要时要对数据加锁防止数据竞争:
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);