为什么使用异步

  异步线程是由线程池负责管理,而多线程,我们可以自己控制,当然在多线程中我们也可以使用线程池。就拿网络扒虫而言,如果使用异步模式去实现,它使用线程池进行管理。异步操作执行时,会将操作丢给线程池中的某个工作线程来完成。当开始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. 九度OJ 1025 最大报销额(01背包)

    题目1025:最大报销额 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:2683 解决:608 题目描述: 现有一笔经费可以报销一定额度的发票.允许报销的发票类型包括买图书(A类).文具( ...

  2. 02_ Windows与Linux双重引导

    1. Grub2引导window. ---------------------步骤1--------------------------------- vim /etc/grub.d/40_custo ...

  3. 关于canvas 易忘属性

    globalAlpha=1//表示全局的一个透明度值 默认值是1 globalCompositeOperation // 默认值="source-over"(Default)

  4. 0627 CMD运行php代码

    打开cmd: 如何在这里面运行php代码 1.调整环境变量:右击电脑->属性->高级系统设置->环境变量 2.新建环境变量: 上部分的用户变量----- 变量名:PHP_HOME   ...

  5. day06

    一.configparser模块 configparser用于处理特定格式的文件,其本质上是利用open来操作文件 1.获取所有节点 import configparser config = conf ...

  6. PHP之路——PHPStudy虚拟主机

    一: Apache/conf/httpd.conf打开以下扩展 LoadModule rewrite_module modules/mod_rewrite.so LoadModule vhost_al ...

  7. wireshark tcp 协议分析

      虽然知道wireshark是抓包神器,只会大概大概用一下,还用一下下tcpdump,略懂一点BPF过滤器,也知道一点怎么用wirkshark过滤相关的报文,但是对于详细的字段的含义,如何查看TCP ...

  8. DZY Loves Colors

    CF #446C:http://codeforces.com/problemset/problem/444/C 题意:给你n个数,大小从1到n,然后又两种操作,1 a b c表示把区间a b 更新为c ...

  9. Actor模型

    Actors模型(Actor model)首先是由Carl Hewitt在1973定义, 由Erlang OTP (Open Telecom Platform) 推广,其 消息传递更加符合面向对象的原 ...

  10. 【HDOJ】4986 Little Pony and Alohomora Part I

    递推.设n个盒子的Spell次数为S(n),期望为E(n).当有n个盒子时,可能第n把钥匙在第n个盒子中,此时的Spell次数应该为(n-1)!+S(n-1):当第n把钥匙不在第n个盒子中,混合排列, ...