为什么使用异步

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

C#中实现异步tcp通信

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

 /// <summary>
/// 启动tcp监听
/// </summary>
public void Start()
{
if (!_isStarted)
{
_isStarted = true;
_server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); #region socket配置
LingerOption lingerOption = new LingerOption(true, );
_server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, lingerOption);
#endregion _server.Blocking = false;
_server.ExclusiveAddressUse = false;
_server.Bind(new IPEndPoint(IPAddress.Any, this._port));
_server.Listen();
Parallel.For(, , i =>
{
_server.BeginAccept(new AsyncCallback(ProcessAccept), _server);
});
}
}

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

  接收数据处理如下:

 /// <summary>
/// 处理传入的连接请求
/// </summary>
private void ProcessAccept(IAsyncResult ar)
{
var s = (Socket)ar.AsyncState;
var remote = s.EndAccept(ar);
var user = new UserToken(this._maxBufferSize) { ID = remote.RemoteEndPoint.ToString(), Client = remote };
remote.BeginReceive(user.ReceiveBuffer, , user.ReceiveBuffer.Length, SocketFlags.None, new AsyncCallback(ProcessReceive),
user);
s.BeginAccept(new AsyncCallback(ProcessAccept), s);
}
 private void ProcessReceive(IAsyncResult ar)
{
var user = (UserToken)ar.AsyncState;
var remote = user.Client;
try
{
if (remote.Connected)
{
var ns = remote.EndReceive(ar); if (ns > )
{
var buffer = new byte[ns]; Buffer.BlockCopy(user.ReceiveBuffer, , buffer, , buffer.Length); user.UnPackage(buffer, (p) =>
{
Interlocked.Increment(ref this._receiveCount);
this.RaiseOnOnReceived(user, p);
}); user.ClearReceiveBuffer(); buffer = null; remote.BeginReceive(user.ReceiveBuffer, , user.ReceiveBuffer.Length, SocketFlags.None, new AsyncCallback(ProcessReceive), user);
}
}
else
{
this.RaiseOnDisConnected(user, new Exception("客户端已断开连接"));
this.CloseClient(user);
}
}
catch (SocketException sex)
{
this.RaiseOnDisConnected(user, sex);
this.CloseClient(user);
}
catch (Exception ex)
{
this.RaiseOnError(user, ex);
this.CloseClient(user);
}
}

  发送数据处理如下:

 /// <summary>
/// 发送信息
/// </summary>
/// <param name="remote"></param>
/// <param name="data"></param>
/// <param name="type"></param>
/// <param name="auth"></param>
private void SendAsync(UserToken remote, byte[] data, TransportType type = TransportType.Heart)
{
try
{
using (var pakage = new TcpPackage(data, type, remote.Auth))
{
remote.Client.BeginSend(pakage.Data, , pakage.Data.Length, SocketFlags.None, new AsyncCallback(EndSend), remote);
} }
catch (SocketException sex)
{
this.RaiseOnDisConnected(remote, sex);
}
catch (Exception ex)
{
this.RaiseOnError(remote, ex);
}
}
 private void EndSend(IAsyncResult ar)
{
var remote = (UserToken)ar.AsyncState;
remote.Client.EndSend(ar);
Interlocked.Increment(ref this._sendCount);
}

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

 /// <summary>
/// 回复心跳
/// </summary>
/// <param name="remote"></param>
/// <param name="package"></param>
private void ReplyHeart(UserToken remote, TcpPackage package)
{
this.SendAsync(remote, null, TransportType.Heart);
}
 /// <summary>
/// 发送信息
/// </summary>
/// <param name="remote"></param>
/// <param name="msg"></param>
public void SendMsg(UserToken remote, byte[] msg)
{
this.SendAsync(remote, msg, TransportType.Message);
}
 /// <summary>
/// 发送文件
/// </summary>
/// <param name="remote"></param>
/// <param name="filePath"></param>
public void SendFile(UserToken remote, string filePath)
{
using (var file = new TransferFileInfo()
{
ID = remote.ID,
FileBytes = File.ReadAllBytes(filePath),
Name = filePath.Substring(filePath.LastIndexOf("\\") + ),
CreateTime = DateTime.Now.Ticks
})
{
var buffer = TransferFileInfo.Serialize(file);
this.SendAsync(remote, buffer, TransportType.File);
buffer = null;
}
}
 /// <summary>
/// 发送文件
/// </summary>
/// <param name="remote"></param>
/// <param name="fileName"></param>
/// <param name="file"></param>
public void SendFile(UserToken remote, string fileName, byte[] file)
{
using (var fileInfo = new TransferFileInfo()
{
ID = remote.ID,
FileBytes = file,
Name = fileName,
CreateTime = DateTime.Now.Ticks
})
{
var buffer = TransferFileInfo.Serialize(fileInfo);
this.SendAsync(remote, buffer, TransportType.File);
buffer = null;
}
}

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

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

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

异步tcp通信——APM.ConsoleDemo

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

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

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

    TCP通信解包 虽说这是一个老生长谈的问题,不过网上基本很少见完整业务:或多或少都没有写完或者存在bug.接收到的数据包可以简单分成:小包.大包.跨包三种情况,根据这三种情况作相对应的拆包处理,示例如 ...

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

    消息推送服务 服务器推送目前流行就是私信.发布/订阅等模式,基本上都是基于会话映射,消息对列等技术实现的:高性能.分布式可以如下解决:会话映射可采用redis cluster等技术实现,消息对列可使用 ...

  3. 异步tcp通信——APM.ConsoleDemo

    APM测试 俗话说麻雀虽小,五脏俱全.apm虽然简单,但是可以实现单机高性能消息推送(可以采用redis.kafka等改造成大型分布式消息推送服务器). 测试demo: using System; u ...

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

    TCP协议下的服务端并发,GIL全局解释器锁,死锁,信号量,event事件,线程q 一.TCP协议下的服务端并发 ''' 将不同的功能尽量拆分成不同的函数,拆分出来的功能可以被多个地方使用 TCP服务 ...

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

    http://mgyongyosi.com/2016/Vuejs-server-side-rendering-with-aspnet-core/ 原作者:Mihály Gyöngyösi 译者:oop ...

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

    UDP协议 (了解) 称之为数据包协议,又称不可靠协议. 特点: 1) 不需要建立链接. 2) 不需要知道对方是否收到. 3) 数据不安全 4) 传输速度快 5)能支持并发 6) 不会粘包 7) 无需 ...

  7. c++ 网络编程(一)TCP/UDP windows/linux 下入门级socket通信 客户端与服务端交互代码

    原文作者:aircraft 原文地址:https://www.cnblogs.com/DOMLX/p/9601511.html c++ 网络编程(一)TCP/UDP  入门级客户端与服务端交互代码 网 ...

  8. 实验09——java基于TCP实现客户端与服务端通信

    TCP通信         需要先创建连接 - 并且在创建连接的过程中 需要经过三次握手        底层通过 流 发送数据 数据没有大小限制        可靠的传输机制 - 丢包重发 包的顺序的 ...

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

    这两天研究了下Socket通信,简单实现的客户端和服务端代码 先上winfrom图片,客户端和服务端一样 服务端代码: using System; using System.Collections.G ...

随机推荐

  1. TCP/IP-IP

    A contented mind is a perpetual feast. "知足长乐" 参考资料:TCP/IP入门经典 (第五版) TCP/IP详解 卷一:协议 一.简介 IP ...

  2. C++ Primer 5th 第11章 关联容器

    练习11.1:描述map 和 vector 的不同. map是关联容器,vector是顺序容器,关联容器与值无关,vector则与值密切相关 练习11.2:分别给出最适合使用 list.vector. ...

  3. 你真的了解console吗?

    对于前端开发者来说,在开发过程中需要监控某些表达式或变量的值的时候,用 debugger 会显得过于笨重,取而代之则是会将值输出到控制台上方便调试.最常用的语句就是console.log(expres ...

  4. 初涉JavaScript模式 (5) : 原型模式 【一】

    什么是原型模式? 原型模式(prototype)是指用原型实例指向创建对象的种类,并且通过拷贝这些原型创建新的对象.--引自JavaScript设计模式 我们创建的每一个函数都有一个prototype ...

  5. JS判断鼠标从哪个方向进入DIV容器

    写的不够高大上 , 不要介意哦... Js: //进去 $(".flash").bind("mouseenter",function(e){ /** the w ...

  6. Delphi Keycode

    Keycode表 字母和数字键的键码值(keyCode) 按键 键码 按键 键码 按键 键码 按键 键码 A 65 J 74 S 83 1 49 B 66 K 75 T 84 2 50 C 67 L ...

  7. ELK beats平台介绍

    原文链接:http://www.tuicool.com/articles/mYjYRb6 beats是一个代理,将不同类型的数据发送到elasticsearch.beats可以直接将数据发送到elas ...

  8. mongodb 教程三

    mongodb 实际上是保存json的数据的结构.当查询 是修改时 key 是可以用''保存. mongodb  插入语句 db.weixin.insert({name:'zhangfeng',age ...

  9. Python实现ID3算法

    自己用Python写的数据挖掘中的ID3算法,现在觉得Python是实现算法的最好工具: 先贴出ID3算法的介绍地址http://wenku.baidu.com/view/cddddaed0975f4 ...

  10. codeproject

    search: http http://www.codeproject.com/Articles/96620/Writing-Http-Handlers-and-Modules-in-IIS-7-5 ...