异步tcp通信——APM.Core 服务端概述

为什么使用异步

  异步线程是由线程池负责管理,而多线程,我们可以自己控制,当然在多线程中我们也可以使用线程池。就拿网络扒虫而言,如果使用异步模式去实现,它使用线程池进行管理。异步操作执行时,会将操作丢给线程池中的某个工作线程来完成。当开始I/O操作的时候,异步会将工作线程还给线程池,这意味着获取网页的工作不会再占用任何CPU资源了。直到异步完成,即获取网页完毕,异步才会通过回调的方式通知线程池。可见,异步模式借助于线程池,极大地节约了CPU的资源。
  注:DMA(Direct Memory Access)直接内存存取,顾名思义DMA功能就是让设备可以绕过处理器,直接由内存来读取资料。通过直接内存访问的数据交换几乎可以不损耗CPU的资源。在硬件中,硬盘、网卡、声卡、显卡等都有直接内存访问功能。异步编程模型就是让我们充分利用硬件的直接内存访问功能来释放CPU的压力。
  两者的应用场景:
    计算密集型工作,采用多线程。
    IO密集型工作,采用异步机制。

C#中实现异步tcp通信

  socket中仅仅需要将Blocking=false即可轻松实现异步,部分示例如下:

 1 /// <summary>
 2         /// 启动tcp监听
 3         /// </summary>
 4         public void Start()
 5         {
 6             if (!_isStarted)
 7             {
 8                 _isStarted = true;
 9                 _server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
10
11                 #region socket配置
12                 LingerOption lingerOption = new LingerOption(true, 30);
13                 _server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, lingerOption);
14                 #endregion
15
16                 _server.Blocking = false;
17                 _server.ExclusiveAddressUse = false;
18                 _server.Bind(new IPEndPoint(IPAddress.Any, this._port));
19                 _server.Listen(1000000);
20                 Parallel.For(0, 1000000, i =>
21                 {
22                     _server.BeginAccept(new AsyncCallback(ProcessAccept), _server);
23                 });
24             }
25         }

  tcp异步中处理接io操作最关键的参数:IAsyncResult,使用一般用begin开始,end结束。

  接收数据处理如下:

 1 /// <summary>
 2         /// 处理传入的连接请求
 3         /// </summary>
 4         private void ProcessAccept(IAsyncResult ar)
 5         {
 6             var s = (Socket)ar.AsyncState;
 7             var remote = s.EndAccept(ar);
 8             var user = new UserToken(this._maxBufferSize) { ID = remote.RemoteEndPoint.ToString(), Client = remote };
 9             remote.BeginReceive(user.ReceiveBuffer, 0, user.ReceiveBuffer.Length, SocketFlags.None, new AsyncCallback(ProcessReceive),
10                 user);
11             s.BeginAccept(new AsyncCallback(ProcessAccept), s);
12         }

 1 private void ProcessReceive(IAsyncResult ar)
 2         {
 3             var user = (UserToken)ar.AsyncState;
 4             var remote = user.Client;
 5             try
 6             {
 7                 if (remote.Connected)
 8                 {
 9                     var ns = remote.EndReceive(ar);
10
11                     if (ns > 0)
12                     {
13                         var buffer = new byte[ns];
14
15                         Buffer.BlockCopy(user.ReceiveBuffer, 0, buffer, 0, buffer.Length);
16
17                         user.UnPackage(buffer, (p) =>
18                         {
19                             Interlocked.Increment(ref this._receiveCount);
20                             this.RaiseOnOnReceived(user, p);
21                         });
22
23                         user.ClearReceiveBuffer();
24
25                         buffer = null;
26
27                         remote.BeginReceive(user.ReceiveBuffer, 0, user.ReceiveBuffer.Length, SocketFlags.None, new AsyncCallback(ProcessReceive), user);
28                     }
29                 }
30                 else
31                 {
32                     this.RaiseOnDisConnected(user, new Exception("客户端已断开连接"));
33                     this.CloseClient(user);
34                 }
35             }
36             catch (SocketException sex)
37             {
38                 this.RaiseOnDisConnected(user, sex);
39                 this.CloseClient(user);
40             }
41             catch (Exception ex)
42             {
43                 this.RaiseOnError(user, ex);
44                 this.CloseClient(user);
45             }
46         }

  发送数据处理如下:

 1 /// <summary>
 2         /// 发送信息
 3         /// </summary>
 4         /// <param name="remote"></param>
 5         /// <param name="data"></param>
 6         /// <param name="type"></param>
 7         /// <param name="auth"></param>
 8         private void SendAsync(UserToken remote, byte[] data, TransportType type = TransportType.Heart)
 9         {
10             try
11             {
12                 using (var pakage = new TcpPackage(data, type, remote.Auth))
13                 {
14                     remote.Client.BeginSend(pakage.Data, 0, pakage.Data.Length, SocketFlags.None, new AsyncCallback(EndSend), remote);
15                 }
16
17             }
18             catch (SocketException sex)
19             {
20                 this.RaiseOnDisConnected(remote, sex);
21             }
22             catch (Exception ex)
23             {
24                 this.RaiseOnError(remote, ex);
25             }
26         }

1 private void EndSend(IAsyncResult ar)
2         {
3             var remote = (UserToken)ar.AsyncState;
4             remote.Client.EndSend(ar);
5             Interlocked.Increment(ref this._sendCount);
6         }

  心跳、消息、文件等逻辑都可以基于发送逻辑来完成

1 /// <summary>
2         /// 回复心跳
3         /// </summary>
4         /// <param name="remote"></param>
5         /// <param name="package"></param>
6         private void ReplyHeart(UserToken remote, TcpPackage package)
7         {
8             this.SendAsync(remote, null, TransportType.Heart);
9         }

1 /// <summary>
2         /// 发送信息
3         /// </summary>
4         /// <param name="remote"></param>
5         /// <param name="msg"></param>
6         public void SendMsg(UserToken remote, byte[] msg)
7         {
8             this.SendAsync(remote, msg, TransportType.Message);
9         }

 1 /// <summary>
 2         /// 发送文件
 3         /// </summary>
 4         /// <param name="remote"></param>
 5         /// <param name="filePath"></param>
 6         public void SendFile(UserToken remote, string filePath)
 7         {
 8             using (var file = new TransferFileInfo()
 9             {
10                 ID = remote.ID,
11                 FileBytes = File.ReadAllBytes(filePath),
12                 Name = filePath.Substring(filePath.LastIndexOf("\\") + 1),
13                 CreateTime = DateTime.Now.Ticks
14             })
15             {
16                 var buffer = TransferFileInfo.Serialize(file);
17                 this.SendAsync(remote, buffer, TransportType.File);
18                 buffer = null;
19             }
20         }

 1 /// <summary>
 2         /// 发送文件
 3         /// </summary>
 4         /// <param name="remote"></param>
 5         /// <param name="fileName"></param>
 6         /// <param name="file"></param>
 7         public void SendFile(UserToken remote, string fileName, byte[] file)
 8         {
 9             using (var fileInfo = new TransferFileInfo()
10             {
11                 ID = remote.ID,
12                 FileBytes = file,
13                 Name = fileName,
14                 CreateTime = DateTime.Now.Ticks
15             })
16             {
17                 var buffer = TransferFileInfo.Serialize(fileInfo);
18                 this.SendAsync(remote, buffer, TransportType.File);
19                 buffer = null;
20             }
21         }

异步tcp通信——APM.Core 服务端概述

异步tcp通信——APM.Core 解包

异步tcp通信——APM.Server 消息推送服务的实现

异步tcp通信——APM.ConsoleDemo

转载请标明本文来源:http://www.cnblogs.com/yswenli/
更多内容欢迎star作者的github:https://github.com/yswenli/APM
如果发现本文有什么问题和任何建议,也随时欢迎交流~

时间: 10-31

异步tcp通信——APM.Core 服务端概述的相关文章

异步tcp通信——APM.Core 解包

TCP通信解包 虽说这是一个老生长谈的问题,不过网上基本很少见完整业务:或多或少都没有写完或者存在bug.接收到的数据包可以简单分成:小包.大包.跨包三种情况,根据这三种情况作相对应的拆包处理,示例如下: 1 /***************************************************************************************************** 2 * 本代码版权归@wenli所有,All Rights Reserved (C)

TCP协议下的服务端并发,GIL全局解释器锁,死锁,信号量,event事件,线程q

TCP协议下的服务端并发,GIL全局解释器锁,死锁,信号量,event事件,线程q 一.TCP协议下的服务端并发 ''' 将不同的功能尽量拆分成不同的函数,拆分出来的功能可以被多个地方使用 TCP服务端实现并发 1.将连接循环和通信循环拆分成不同的函数 2.将通信循环做成多线程 ''' # 服务端 import socket from threading import Thread ''' 服务端 要有固定的IP和PORT 24小时不间断提供服务 能够支持并发 ''' server = sock

Vue.js与 ASP.NET Core 服务端渲染功能整合

http://mgyongyosi.com/2016/Vuejs-server-side-rendering-with-aspnet-core/ 原作者:Mihály Gy?ngy?si 译者:oopsguy.com 我真的很喜欢在前端使用 Vue.js,Vue 服务端渲染直到第二个版本才被支持. 在本例中,我想展示如何将 Vue.js  服务端渲染功能整合 ASP.NET Core. 我们在服务端使用了 Microsoft.AspNetCore.SpaServices 包,该包提供 ASP.N

网络编程 UDP协议 TCP局域网客户端与服务端上传下载电影示例

UDP协议 (了解) 称之为数据包协议. 特点: 1) 不需要建立链接. 2) 不需要知道对方是否收到. 3) 数据不安全 4) 传输速度快 5)能支持并发 6) 不会粘包 7) 无需先启动服务端再启动客户端 优点: - 传输速度快 - 能支持并发 - 不会粘包 缺点: - 数据不安全, 容易丢失 应用场景: 早期的QQ聊天室. # server端 import socket # socket.SOCK_DGRAM ---> UPD协议 server = socket.socket(type=s

采用异步socket实现客户端和服务端通信的demo

MAC系统基于UNIX的核心系统增强了系统的稳定性.性能以及响应能力.由于unix需要付费,以及版本基本上不更新,很多采用unix系统的电脑转用linux,unix处于停滞不前状态,而linux由于是开源的,免费的,所以全球很多技术大牛在不断改进它,给它增加新技术,增加新理念,是它日新月异的发展.所以mac os后期主要借鉴linux的新技术,所以现在的mac os更像linux而非unix.可以说苹果系统是从linux和unix演化而来的,所以linux的socket的编程对苹果系统仍然有效.

Socket通信客户端和服务端代码

这两天研究了下Socket通信,简单实现的客户端和服务端代码 先上winfrom图片,客户端和服务端一样 服务端代码: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; usin

.NET 即时通信,WebSocket服务端实例

即时通信常用手段 1.第三方平台 谷歌.腾讯 环信等多如牛毛,其中谷歌即时通信是免费的,但免费就是免费的并不好用.其他的一些第三方一般收费的,使用要则限流(1s/限制x条消息)要么则限制用户数. 但稳定性什么都还不错,又能将服务压力甩出 2.System.Net.Sockets.Socket,也能写一套较好的服务器端.在.NET 4.5之前用较多,使用起来麻烦.需要对数据包进行解析等操作(但貌似网上有对超长包的处理方法) 3.System.Net.WebSockets.WebSocket,这个,

WCF 通过net tcp 协议 ,在服务端服务器和客户端服务器之间传输数据,注意配置事项

1. 特别注意  binding name="BindingBehaviorConfiguration" (名字可以随意取,但是必须要服务端和客户端保持一致) bindingConfiguration="BindingBehaviorConfiguration" 如何没有配置保持一致:出现:服务器已拒绝客户端凭据 如果没有配置:security mode="None", 出现的现象:服务器已拒绝客户端凭据 //----服务端配置实例: <?

java网络编程TCP传输—流操作—服务端反馈与客户端接收

在读取完流后,服务端会向客户端返回一些数据,告诉客户端,已经写完了. 在这里和”流操作—拿到源后的写入动作“差不多,客户端同样以byte与Buffered两种缓冲读取作为例子,同时,.也是希望大家给补充. 1.利用OutputStream向客户端回写,客户端用byte作为缓冲接收 向客户端回写: 1 //获取socket输出流,将上传成功字样传给客户端 2 OutputStream out=s.getOutputStream(); 3 out.write("上传成功".getBytes