为什么使用异步

  异步线程是由线程池负责管理,而多线程,我们可以自己控制,当然在多线程中我们也可以使用线程池。就拿网络扒虫而言,如果使用异步模式去实现,它使用线程池进行管理。异步操作执行时,会将操作丢给线程池中的某个工作线程来完成。当开始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. 【USACO 2.1.2】法雷序列

    [问题描述]     对任意给定的一个自然数 n(n<=160), 将分母小于等于 n 的不可约的真分数按上升的次序排序 , 并且在第一个分数前加上 0/1, 而在最后一个分数后加上 1/1, ...

  2. 测试最新的log4cplus1.1.2版

    #include "stdafx.h" #include <sstream> class AB{ public:     void do_test()     {    ...

  3. Delphi-LowerCase 函数

    函数名称 LowerCase 所在单元 System.SysUtils 函数原型 function LowerCase(const S: string): string; 函数功能 将字符串中所有的大 ...

  4. TCP\UDP链接的异同

    简单的说TCP与UDP的区别是有无连接状态.TCP是有连接状态的,而UDP没有,所以TCP是一种比较安全的通讯协议,而UDP则比较方便 TCP 127.0.0.1:1026 0.0.0.0:0 LIS ...

  5. APP如何设计才能适配iphone6/plus和iphone5

    随着苹果发布两种新尺寸的大屏iPhone 6,iOS平台尺寸适配问题终于还是来了,移动设计全面进入"杂屏"时代.看看下面三款iPhone尺寸和分辨率数据就知道屏幕有多杂了. 移动a ...

  6. 3d touch 应用 2 -备用

    一.引言 在iphone6s问世之后,很多果粉都争先要体验3D Touch给用户带来的额外维度上的交互,这个设计之所以叫做3D Touch,其原理上是增加了一个压力的感触,通过区分轻按和重按来进行不同 ...

  7. 关于 mod_python

    首先声明 本文 翻译 别人的文章,文章的作者是 mod_python 项目的负责人,目前 mod_python已由 Apache维护.原文地址: http://www.onlamp.com/pub/a ...

  8. Solr4.8.0源码分析(12)之Lucene的索引文件(5)

    Solr4.8.0源码分析(12)之Lucene的索引文件(5) 1. 存储域数据文件(.fdt和.fdx) Solr4.8.0里面使用的fdt和fdx的格式是lucene4.1的.为了提升压缩比,S ...

  9. HBase MemStoreFlusher

    HBase MemStore Flush由类org.apache.hadoop.hbase.regionserver.MemStoreFlusher实现,具体表现为HRegionServer中的一个实 ...

  10. javascript正则表达式(二)——方法

    正则表达式规则见:http://www.cnblogs.com/wishyouhappy/p/3756812.html,下面说明相关方法 String相关方法 概括: search() replace ...