异步tcp通信——APM.Core 服务端概述
为什么使用异步
异步线程是由线程池负责管理,而多线程,我们可以自己控制,当然在多线程中我们也可以使用线程池。就拿网络扒虫而言,如果使用异步模式去实现,它使用线程池进行管理。异步操作执行时,会将操作丢给线程池中的某个工作线程来完成。当开始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 服务端概述的更多相关文章
- 异步tcp通信——APM.Core 解包
TCP通信解包 虽说这是一个老生长谈的问题,不过网上基本很少见完整业务:或多或少都没有写完或者存在bug.接收到的数据包可以简单分成:小包.大包.跨包三种情况,根据这三种情况作相对应的拆包处理,示例如 ...
- 异步tcp通信——APM.Server 消息推送服务的实现
消息推送服务 服务器推送目前流行就是私信.发布/订阅等模式,基本上都是基于会话映射,消息对列等技术实现的:高性能.分布式可以如下解决:会话映射可采用redis cluster等技术实现,消息对列可使用 ...
- 异步tcp通信——APM.ConsoleDemo
APM测试 俗话说麻雀虽小,五脏俱全.apm虽然简单,但是可以实现单机高性能消息推送(可以采用redis.kafka等改造成大型分布式消息推送服务器). 测试demo: using System; u ...
- TCP协议下的服务端并发,GIL全局解释器锁,死锁,信号量,event事件,线程q
TCP协议下的服务端并发,GIL全局解释器锁,死锁,信号量,event事件,线程q 一.TCP协议下的服务端并发 ''' 将不同的功能尽量拆分成不同的函数,拆分出来的功能可以被多个地方使用 TCP服务 ...
- Vue.js与 ASP.NET Core 服务端渲染功能整合
http://mgyongyosi.com/2016/Vuejs-server-side-rendering-with-aspnet-core/ 原作者:Mihály Gyöngyösi 译者:oop ...
- 网络编程 UDP协议 TCP局域网客户端与服务端上传下载电影示例
UDP协议 (了解) 称之为数据包协议,又称不可靠协议. 特点: 1) 不需要建立链接. 2) 不需要知道对方是否收到. 3) 数据不安全 4) 传输速度快 5)能支持并发 6) 不会粘包 7) 无需 ...
- c++ 网络编程(一)TCP/UDP windows/linux 下入门级socket通信 客户端与服务端交互代码
原文作者:aircraft 原文地址:https://www.cnblogs.com/DOMLX/p/9601511.html c++ 网络编程(一)TCP/UDP 入门级客户端与服务端交互代码 网 ...
- 实验09——java基于TCP实现客户端与服务端通信
TCP通信 需要先创建连接 - 并且在创建连接的过程中 需要经过三次握手 底层通过 流 发送数据 数据没有大小限制 可靠的传输机制 - 丢包重发 包的顺序的 ...
- Socket通信客户端和服务端代码
这两天研究了下Socket通信,简单实现的客户端和服务端代码 先上winfrom图片,客户端和服务端一样 服务端代码: using System; using System.Collections.G ...
随机推荐
- Delphi笔记(GL_Scene安装及简单使用)
前一段时间,需要弄一个四轴的监控平台,看了匿名的上位机后,十分感兴趣.于是我也想自己也弄一个上位机来玩玩,在将串口通讯调好了以后,就开始好奇那个3D模型是怎么弄的.在网上面查找了很多资料,由于我用的是 ...
- 素数判定 AC 杭电
素数判定 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submi ...
- iOS6 自动布局 入门–Auto Layout(转)
iOS6 自动布局 入门–Auto Layout(转) 标签: 杂谈 目前为止,即使你的界面设计是在合理的复杂度内,你也必须要为之写许多代码来适应变化的布局.现在我相信你会很高兴听到这种情况将不会 ...
- 构建高可用web站点学习(三)
分布式的构建 做为网站访问的生命线(数据访问),当然也可以采用分布式的方法来减轻单台服务器的访问压力.之前有讲过Memcached的分布式,但是Memcached服务器互不通信,所以我们也提过redi ...
- 转:CodeCube提供可共享、可运行的代码示例
CodeCube是一个新服务和开源项目,旨在让开发者能够通过浏览器以一种安全的方式分享并运行代码示例从而提升协作. 最初发布的服务可以从codecube.io上获取,支持Ruby.Python.Go及 ...
- 【JavsScript】关于javascript的路线
Client JS: Level 1 基本对象的掌握----------------------------------------->Library(兼容)/Widget(UI+功能)---- ...
- DZY Loves Colors
CF #446C:http://codeforces.com/problemset/problem/444/C 题意:给你n个数,大小从1到n,然后又两种操作,1 a b c表示把区间a b 更新为c ...
- ASP.NET 查询客户端请求IP地址
public class CheckIP { #region 获取浏览器版本号 /// <summary> /// 获 ...
- 项目mysql数据导入数据的Java程序
最近写的一个数据库导入数据的程序,有兴趣的同学可以参考一下: 这个程序是针对mysql数据库的,在本地或服务器上运行,主要的需求还是,针对项目的某些bug修复 后,客户的数据要搬到新表上来,避免新版本 ...
- sqlserver2012的审计功能的相关理解
1.sqlserver2012可以做实例的审计,以及数据库的审计,基本包括了所有的操作.可以符合我们的要求. 2.审计功能需要实例级别的配置数据库级别的配置,实例上建立“审核”,数据库上建立“数据 ...