浅谈C#网络编程(二)

异步IO

上篇提到用多线程处理多个阻塞同步IO而实现并发服务端,这种模式在连接数量比较小的时候非常适合,一旦连接过多,性能会急速下降。 在大多数服务端网络软件中会采用一种异步IO的方式来提高性能。

  • 同步IO方式:连接Receive请求->等待->等待->接收成功
  • 异步IO方式:连接Receive请求->立即返回->事件或回调通知

采用异步IO方式,意味着单线程可以处理多个请求了,连接发起一个Receive请求后,当前线程可以立即去做别的事情,当数据接收完毕通知线程处理即可。 其数据接收分2部分:

  1. 数据从别的机器发送内核缓冲区
  2. 内核缓冲区拷贝到用户缓冲区

第二部分示例代码:

byte[] msg = new byte[256]; socket.Receive(msg);

介绍这2部分的目的是方便区分其他几种方式。 对于用户程序来说,同步IO和异步IO的区别在于第二部分是否需要等待。

非阻塞式同步IO

非阻塞式同步IO,由同步IO延伸出来,把这个名词拆分成2部分描述:

  1. 非阻塞式,指的是上节"数据从别的机器发送内核缓冲区"部分是非阻塞的。
  2. 同步IO,指的是上节"内核缓冲区拷贝到用户缓冲区"部分是等待的。

既然是第一部分是非阻塞的,那就需要一种方法得知什么时候内核缓冲区是OK的。 设置非阻塞模式后,在连接调用Receive方法时,会立即返回一个标记,告知用户程序内核缓存区有没有数据,如果有数据开始进行第二部分操作,从内核缓冲区拷贝到用户程序缓冲区。 由于系统会返回个标记,那可以通过轮询方式来判断内核缓冲区是否OK。

设置非阻塞模式参考代码:

SocketInformation sif=new SocketInformation();
sif.Options=SocketInformationOptions.NonBlocking;
sif.ProtocolInformation = new byte[24];
Socket socket = new Socket(sif);

轮询参考代码:

while(true) 
{
byte[] msg = new byte[256];
var temp = socket.Receive(msg);
if (temp=="OK"){
//do something
}else{ continue }
}

 这种方式近乎淘汰了,了解即可。

基于回调的异步IO

上面介绍过:

  • 异步IO方式:连接Receive请求->立即返回->事件或回调通知

当回调到执行时,数据已经在用户程序缓冲区已经准备好了,在回调代码中对这部分数据进行相应的逻辑即可。

发出接收请求:

 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);

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏林德熙的博客

win10 uwp 隐藏实时可视化

12620
来自专栏凉城

文章内的新浪短网址https无法访问解决办法!

24440
来自专栏Java成神之路

Eclipse_debug异常_Source not found

在eclipse中,打了断点之后运行代码,出现debug异常:Source not found,如下图

8420
来自专栏蘑菇先生的技术笔记

浅谈C#网络编程(二)

21440
来自专栏Jed的技术阶梯

通过已有的虚拟机克隆四台虚拟机

环境准备:一个已经安装好的虚拟机 要求: 删除了 /etc/udev/rules.d/70-persistent-net.rules 这个文件后,关机,保存...

28020
来自专栏13blog.site

springboot开启access_log日志输出

由于在调试时需要查看access_log日志,但是springboot默认并没有开启,因此查看了一下文档,在springboot的配置文件中添加如下设置,即可将...

57150
来自专栏一枝花算不算浪漫

[常见问题]Project facet Java versin 1.8 is not support.

37870
来自专栏difcareer的技术笔记

编译私有的Android SDK

某些原因需要自己编译一个Android SDK,比如放开某些API接口。本文记录一下编译过程。

8120
来自专栏优启梦

文章内的新浪短网址https无法访问解决办法!

大家都知道最近新浪短网址出问题了! 以前蓝奏云、文章分享出来的地址都是https://t.cn的 导致丢失好多量! 一个一个修改太麻烦了,我们只能暂时将 htt...

45570
来自专栏云计算教程系列

如何在Ubuntu 18.04上配置Node.js生产环境应用

Node.js是一个开源JavaScript运行环境,用于构建服务器端和网络应用程序。该平台可在Linux,macOS,FreeBSD和Windows上运行。虽...

17030

扫码关注云+社区

领取腾讯云代金券