介绍开源的.net通信框架NetworkComms框架 源码分析(二十一 )TCPConnectionListener
原文网址: http://www.cnblogs.com/csdev
Networkcomms 是一款C# 语言编写的TCP/UDP通信框架 作者是英国人 以前是收费的 目前作者已经开源 许可是:Apache License v2
开源地址是:https://github.com/MarcFletcher/NetworkComms.Net
TCP连接监听器
/// <summary>
/// A TCP connection listener
/// TCP连接监听器
/// </summary>
public class TCPConnectionListener : ConnectionListenerBase
{
#if WINDOWS_PHONE || NETFX_CORE
/// <summary>
/// The equivalent TCPListener class in windows phone
/// WP系统中与TCPListener类相对应的类
/// </summary>
StreamSocketListener listenerInstance;
#else
/// <summary>
/// The .net TCPListener class.
/// .net中TCPListener类
/// </summary>
TcpListener listenerInstance;
/// <summary>
/// SSL options that are associated with this listener
/// 监听器相对应的SSL选项
/// </summary>
public SSLOptions SSLOptions { get; private set; }
#endif
/// <summary>
/// Create a new instance of a TCP listener
/// 创建一个新的TCP监听器实例
/// </summary>
/// <param name="sendReceiveOptions">The SendReceiveOptions to use with incoming data on this listener 此监听器上接收进入的数据所使用的收发参数 </param>
/// <param name="applicationLayerProtocol">If enabled NetworkComms.Net uses a custom
/// application layer protocol to provide useful features such as inline serialisation,
/// transparent packet transmission, remote peer handshake and information etc. We strongly
/// recommend you enable the NetworkComms.Net application layer protocol.</param>
/// applicationLayerProtocol 应用层协议状态 我们强烈建议您启用此项,使得networkcomms能为您提供内部序列化,透明数据包传送,远程端点握手等功能。
/// 只有与其他语言进行通信时,此项才设置为禁用
/// <param name="allowDiscoverable">Determines if the newly created <see cref="ConnectionListenerBase"/> will be discoverable if <see cref="Tools.PeerDiscovery"/> is enabled.</param>
/// allowDiscoverable 是否允许被发现 此项与networkcomms中一项端点自动扫描功能有关
public TCPConnectionListener(SendReceiveOptions sendReceiveOptions,
ApplicationLayerProtocolStatus applicationLayerProtocol, bool allowDiscoverable = false)
:base(ConnectionType.TCP, sendReceiveOptions, applicationLayerProtocol, allowDiscoverable)
{
#if !WINDOWS_PHONE && !NETFX_CORE
SSLOptions = new SSLOptions();
#endif
}
#if !WINDOWS_PHONE && !NETFX_CORE
/// <summary>
/// Create a new instance of a TCP listener
/// 创建一个新的TCP监听器实例
/// </summary>
/// <param name="sendReceiveOptions">The SendReceiveOptions to use with incoming data on this listener 此监听器上接收进入的数据所使用的收发参数 </param>
/// <param name="applicationLayerProtocol">If enabled NetworkComms.Net uses a custom
/// application layer protocol to provide useful features such as inline serialisation,
/// transparent packet transmission, remote peer handshake and information etc. We strongly
/// recommend you enable the NetworkComms.Net application layer protocol.</param>
/// applicationLayerProtocol 应用层协议状态 我们强烈建议您启用此项,使得networkcomms能为您提供内部序列化,透明数据包传送,远程端点握手等功能。
/// 只有与其他语言进行通信时,此项才设置为禁用
/// <param name="allowDiscoverable">Determines if the newly created <see cref="ConnectionListenerBase"/> will be discoverable if <see cref="Tools.PeerDiscovery"/> is enabled.</param>
/// allowDiscoverable 是否允许被发现 此项与networkcomms中一项端点自动扫描功能有关
public TCPConnectionListener(SendReceiveOptions sendReceiveOptions,
ApplicationLayerProtocolStatus applicationLayerProtocol, SSLOptions sslOptions, bool allowDiscoverable = false)
: base(ConnectionType.TCP, sendReceiveOptions, applicationLayerProtocol, allowDiscoverable)
{
this.SSLOptions = sslOptions;
}
#endif
/// <inheritdoc />
internal override void StartListening(EndPoint desiredLocalListenEndPoint, bool useRandomPortFailOver)
{
if (desiredLocalListenEndPoint.GetType() != typeof(IPEndPoint)) throw new ArgumentException("Invalid desiredLocalListenEndPoint type provided.", "desiredLocalListenEndPoint");
if (IsListening) throw new InvalidOperationException("Attempted to call StartListening when already listening.");
IPEndPoint desiredLocalListenIPEndPoint = (IPEndPoint)desiredLocalListenEndPoint;
try
{
#if WINDOWS_PHONE || NETFX_CORE
listenerInstance = new StreamSocketListener();
listenerInstance.ConnectionReceived += newListenerInstance_ConnectionReceived;
listenerInstance.BindEndpointAsync(new Windows.Networking.HostName(desiredLocalListenIPEndPoint.Address.ToString()), desiredLocalListenIPEndPoint.Port.ToString()).AsTask().Wait();
#else
listenerInstance = new TcpListener(desiredLocalListenIPEndPoint);
listenerInstance.Start();
listenerInstance.BeginAcceptTcpClient(TCPConnectionReceivedAsync, null);
#endif
}
catch (SocketException)
{
//If the port we wanted is not available
//如果我们希望监听的端口已经被占用 useRandomPortFailOver(是否随机指定一个新端口)
if (useRandomPortFailOver)
{
try
{
#if WINDOWS_PHONE || NETFX_CORE
listenerInstance.BindEndpointAsync(new Windows.Networking.HostName(desiredLocalListenIPEndPoint.Address.ToString()), "").AsTask().Wait();
#else
listenerInstance = );
listenerInstance.Start();
listenerInstance.BeginAcceptTcpClient(TCPConnectionReceivedAsync, null);
#endif
}
catch (SocketException)
{
//If we get another socket exception this appears to be a bad IP. We will just ignore this IP
//如果我们重新指定端口,还是没有监听成功,则可能是IP地址的问题
if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Error("It was not possible to open a random port on " + desiredLocalListenIPEndPoint.Address + ". This endPoint may not support listening or possibly try again using a different port.");
throw new CommsSetupShutdownException("It was not possible to open a random port on " + desiredLocalListenIPEndPoint.Address + ". This endPoint may not support listening or possibly try again using a different port.");
}
}
else
{
if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Error("It was not possible to open port #" + desiredLocalListenIPEndPoint.Port.ToString() + " on " + desiredLocalListenIPEndPoint.Address + ". This endPoint may not support listening or possibly try again using a different port.");
throw new CommsSetupShutdownException("It was not possible to open port #" + desiredLocalListenIPEndPoint.Port.ToString() + " on " + desiredLocalListenIPEndPoint.Address + ". This endPoint may not support listening or possibly try again using a different port.");
}
}
#if WINDOWS_PHONE || NETFX_CORE
this.LocalListenEndPoint = new IPEndPoint(desiredLocalListenIPEndPoint.Address, int.Parse(listenerInstance.Information.LocalPort));
#else
this.LocalListenEndPoint = (IPEndPoint)listenerInstance.LocalEndpoint;
#endif
this.IsListening = true;
}
/// <inheritdoc />
internal override void StopListening()
{
IsListening = false;
try
{
#if WINDOWS_PHONE || NETFX_CORE
listenerInstance.Dispose();
#else
listenerInstance.Stop();
#endif
}
catch (Exception) { }
}
#if WINDOWS_PHONE || NETFX_CORE
private void newListenerInstance_ConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
{
try
{
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Parse(args.Socket.Information.LocalAddress.DisplayName.ToString()), int.Parse(args.Socket.Information.LocalPort));
IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Parse(args.Socket.Information.RemoteAddress.DisplayName.ToString()), int.Parse(args.Socket.Information.RemotePort));
ConnectionInfo newConnectionInfo = new ConnectionInfo(ConnectionType.TCP, remoteEndPoint, localEndPoint, ApplicationLayerProtocol, this);
TCPConnection.GetConnection(newConnectionInfo, NetworkComms.DefaultSendReceiveOptions, args.Socket, true);
}
catch (ConfirmationTimeoutException)
{
//If this exception gets thrown its generally just a client closing a connection almost immediately after creation
}
catch (CommunicationException)
{
//If this exception gets thrown its generally just a client closing a connection almost immediately after creation
}
catch (ConnectionSetupException)
{
//If we are the server end and we did not pick the incoming connection up then tooo bad!
}
catch (SocketException)
{
//If this exception gets thrown its generally just a client closing a connection almost immediately after creation
}
catch (Exception ex)
{
//For some odd reason SocketExceptions don't always get caught above, so another check
if (ex.GetBaseException().GetType() != typeof(SocketException))
{
//Can we catch the socketException by looking at the string error text?
if (ex.ToString().StartsWith("System.Net.Sockets.SocketException"))
LogTools.LogException(ex, "ConnectionSetupError_SE");
else
LogTools.LogException(ex, "ConnectionSetupError");
}
}
}
#else
/// <summary>
/// Async method for handling up new incoming TCP connections
/// 处理新的TCP连接的异步方法
/// </summary>
private void TCPConnectionReceivedAsync(IAsyncResult ar)
{
if (!IsListening)
return;
try
{
TcpClient newTCPClient = listenerInstance.EndAcceptTcpClient(ar);
ConnectionInfo newConnectionInfo = new ConnectionInfo(ConnectionType.TCP, (IPEndPoint)newTCPClient.Client.RemoteEndPoint, (IPEndPoint)newTCPClient.Client.LocalEndPoint, ApplicationLayerProtocol, this);
if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Info("New incoming TCP connection from " + newConnectionInfo);
//We have to use our own thread pool here as the performance of the .Net one is awful
//此处我们使用了networkcomms自带的自定义线程池 其性能超越了.net自带的线程池
NetworkComms.IncomingConnectionEstablishThreadPool.EnqueueItem(QueueItemPriority.Normal, new WaitCallback((obj) =>
{
#region Pickup The New Connection
try
{
TCPConnection.GetConnection(newConnectionInfo, ListenerDefaultSendReceiveOptions, newTCPClient, true, SSLOptions);
}
catch (ConfirmationTimeoutException)
{
//If this exception gets thrown its generally just a client closing a connection almost immediately after creation
//如果此处抛出异常 一般为客户端创建连接后立即关闭了连接
}
catch (CommunicationException)
{
//If this exception gets thrown its generally just a client closing a connection almost immediately after creation
// //如果此处抛出异常 一般为客户端创建连接后立即关闭了连接
}
catch (ConnectionSetupException)
{
//If we are the server end and we did not pick the incoming connection up then tooo bad!
//如果我们是服务器端 我们没有接收到进入的连接
}
catch (SocketException)
{
//If this exception gets thrown its generally just a client closing a connection almost immediately after creation
// //如果此处抛出异常 一般为客户端创建连接后立即关闭了连接
}
catch (Exception ex)
{
//For some odd reason SocketExceptions don't always get caught above, so another check
//由于一些未知的原因 上面的代码不能捕捉到所有的异常 所以我们还要尽行一些检测
if (ex.GetBaseException().GetType() != typeof(SocketException))
{
//Can we catch the socketException by looking at the string error text?
//通过检测字符型错误信息来捕捉 socket异常
if (ex.ToString().StartsWith("System.Net.Sockets.SocketException"))
LogTools.LogException(ex, "ConnectionSetupError_SE");
else
LogTools.LogException(ex, "ConnectionSetupError");
}
}
#endregion
}), null);
}
catch (SocketException)
{
//如果此处抛出异常 一般为客户端创建连接后立即关闭了连接
}
catch (Exception ex)
{
//For some odd reason SocketExceptions don't always get caught above, so another check
//由于一些未知的原因 上面的代码不能捕捉到所有的异常 所以我们还要尽行一些检测
if (ex.GetBaseException().GetType() != typeof(SocketException))
{
//Can we catch the socketException by looking at the string error text?
if (ex.ToString().StartsWith("System.Net.Sockets.SocketException"))
LogTools.LogException(ex, "ConnectionSetupError_SE");
else
LogTools.LogException(ex, "ConnectionSetupError");
}
}
finally
{
listenerInstance.BeginAcceptTcpClient(TCPConnectionReceivedAsync, null);
}
}
#endif
}
介绍开源的.net通信框架NetworkComms框架 源码分析(二十一 )TCPConnectionListener的更多相关文章
- DotNetty网络通信框架学习之源码分析
DotNetty网络通信框架学习之源码分析 有关DotNetty框架,网上的详细资料不是很多,有不多的几个博友做了简单的介绍,也没有做深入的探究,我也根据源码中提供的demo做一下记录,方便后期查阅. ...
- 框架-springmvc源码分析(二)
框架-springmvc源码分析(二) 参考: http://www.cnblogs.com/leftthen/p/5207787.html http://www.cnblogs.com/leftth ...
- 深入理解分布式调度框架TBSchedule及源码分析
简介 由于最近工作比较忙,前前后后花了两个月的时间把TBSchedule的源码翻了个底朝天.关于TBSchedule的使用,网上也有很多参考资料,这里不做过多的阐述.本文着重介绍TBSchedule的 ...
- 设计模式(十五)——命令模式(Spring框架的JdbcTemplate源码分析)
1 智能生活项目需求 看一个具体的需求 1) 我们买了一套智能家电,有照明灯.风扇.冰箱.洗衣机,我们只要在手机上安装 app 就可以控制对这些家电工作. 2) 这些智能家电来自不同的厂家,我们不想针 ...
- 设计模式(二十一)——解释器模式(Spring 框架中SpelExpressionParser源码分析)
1 四则运算问题 通过解释器模式来实现四则运算,如计算 a+b-c 的值,具体要求 1) 先输入表达式的形式,比如 a+b+c-d+e, 要求表达式的字母不能重复 2) 在分别输入 a ,b, c, ...
- $Django cbv源码分析 djangorestframework框架之APIView源码分析
1 CBV的源码分析 #视图 class login (View): pass #路由 url(r'^books/$', views.login.as_view()) #阅读源码: #左侧工程栏--- ...
- ABP源码分析二十六:核心框架中的一些其他功能
本文是ABP核心项目源码分析的最后一篇,介绍一些前面遗漏的功能 AbpSession AbpSession: 目前这个和CLR的Session没有什么直接的联系.当然可以自定义的去实现IAbpSess ...
- ④NuPlayer播放框架之Renderer源码分析
[时间:2016-11] [状态:Open] [关键词:android,nuplayer,开源播放器,播放框架,渲染器,render] 0 导读 之前我们分析了NuPlayer的实现代码,本文将重点聚 ...
- ⑤NuPlayer播放框架之GenericSource源码分析
[时间:2017-01] [状态:Open] [关键词:android,nuplayer,开源播放器,播放框架,GenericSource] 0 导读 GenericSource是NuPlayer:: ...
- ③NuPlayer播放框架之类NuPlayer源码分析
[时间:2016-10] [状态:Open] [关键词:android,nuplayer,开源播放器,播放框架] 0 引言 差不多一个月了,继续分析AOSP的播放框架的源码.这次我们需要深入分析的是N ...
随机推荐
- 2、CC2541芯片中级教程-OSAL操作系统(进一步了解-OLED && 普通按键和5方向按键-中断!!!)这个系统驱动层和应用层不一样~
本文根据一周CC2541笔记汇总得来—— 适合概览和知识快速索引—— 全部链接: 中级教程-OSAL操作系统\OSAL操作系统-实验01 OSAL初探 [插入]SourceInsight-工程建立方法 ...
- NanoProfiler - 适合生产环境的性能监控类库 之 基本功能篇
背景 NanoProfiler是一个EF Learning Labs出品的免费性能监控类库(即将开源).它的思想和使用方式类似于MiniProfiler的.但是,设计理念有较大差异. MiniProf ...
- Linux网络编程系列-套接口选项控制
获取和设置套接口选项的方法有: getsockopt/setsockopt fcntl ioctl getsockopt/setsockopt 这两个函数仅用于套接口(socket)的设置,另外两个函 ...
- ehcache2拾遗之copyOnRead,copyOnWrite
问题描述 缓存在提升应用性能,提高访问效率上都是至关重要的一步.ehcache也是广为使用的缓存之一.但是如果将一个可变的对象(如普通的POJO/List/Map等)存入缓存中,会导致怎样潜在的问题. ...
- fir.im Weekly - 一切从知识重构开始
一年之计在于春,大自然开始了新元素的重构.你的知识库是否也该重构更新呢? 本期 fir.im Weekly 包含最新的Android.iOS 开发工具.源码和好玩的UI 动画分享,希望对你有用. Sw ...
- java连接数据库的模糊查询
1:模糊查询是比较常见的一种查询方式,例如在订单表中,包含有订单的具体日期.如果要查询某年某月的订单信息,最好的方式就是使用模糊查询.进行模糊查询需要使用关键字LIKE.在使用LIKE关键字进行模糊查 ...
- 开源项目IPProxys的使用
前几天看了一下github上,IPProxys开源项目(https://github.com/qiyeboy/IPProxys)快100star了,看来大家对这个项目还是比较感兴趣的.最近一直没更新文 ...
- 快速入门系列--WebAPI--03框架你值得拥有
接下来进入的是俺在ASP.NET学习中最重要的WebAPI部分,在现在流行的互联网场景下,WebAPI可以和HTML5.单页应用程序SPA等技术和理念很好的结合在一起.所谓ASP.NET WebAPI ...
- java JFileChooser选择文件和保存文件
//文件过滤器import java.io.File; import javax.swing.filechooser.FileFilter; public class MyFilter extends ...
- python--基础学习(一)开发环境搭建,体验HelloWorld
python学习之前 最近想用python写爬虫,由于之前没接触过,所以从零开始,找了技术博文大概了解下基础. 印象比较深的是"python你不去认识它,可能没什么,一旦你认识了它,你就会爱 ...