介绍开源的.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 ...
随机推荐
- 厚积薄发,拥抱 .NET 2016
厚积薄发这个词是高三英语老师在高考前写在黑板上,高中三年努力这么久,是时候迎面而上,冲刺向前.所以,一想到.NET 2016,脑海里蹦出的第一个词就是它. .NET 2016 是 .NET 一次质的飞 ...
- Oracle日期语言修改
-- value带有两个参数,第一个指下限,第二个指上限,将会生成下限到上限之间的数字,但不包含上限.select ceil(dbms_random.value(1000,9999)) from du ...
- javascript事件监听与事件委托
事件监听与事件委托 在js中,常用到element.addEventListener()来进行事件的监听.但是当页面中存在大量需要绑定事件的元素时,这种方式可能会带来性能影响.此时,我们可以用事件 ...
- 缓存篇(Cache)~第三回 HttpModule实现网页的文件级缓存
返回目录 再写完缓存篇第一回之后,得到了很多朋友的好评和来信,所以,决定加快步伐,尽快把剩下的文章写完,本篇是第三回,主要介绍使用HttpModule实现的文件级缓存,在看本文之前,大家需要限度Htt ...
- MVVM架构~knockoutjs系列之验证信息自定义输出~续
返回目录 上一讲中,我以一个实际中的例子说明了knockoutjs的自定义验证功能,在使用过程中,出现了一个问题,当然了不是问题,只是一种需求,上一讲中自定义验证的表现是:当页面加载后,自动显示有问题 ...
- 将不确定变为确定~transactionscope何时提升为分布式事务~SQL2005与SQL2008不同
回到目录 Transactionscope何时被提升为分布式事务,即时要触发msdtc服务,这个问题与数据库版本有关,在前面的文章中,我的MSTDC系列出现了多个版本,有一点没有说清楚,测试的环境不同 ...
- 模糊测试——强制发掘安全漏洞的利器(Jolt 大奖精选丛书)
模糊测试——强制发掘安全漏洞的利器(Jolt 大奖精选丛书) [美]Sutton, M.Greene, A.Amini, P. 著 段念赵勇译 ISBN 978-7-121-21083-9 2013年 ...
- iOS开发——网络使用技术OC篇&网络爬虫-使用正则表达式抓取网络数据
网络爬虫-使用正则表达式抓取网络数据 关于网络数据抓取不仅仅在iOS开发中有,其他开发中也有,也叫网络爬虫,大致分为两种方式实现 1:正则表达 2:利用其他语言的工具包:java/Python 先来看 ...
- SQLServer清空数据库中所有的表并且ID自动归0
exec sp_MSforeachtable 'Truncate Table ?'
- 【工具】CodeSmith Generator 7.0.2激活步骤
学过三层的人应该认识CodeSmith Generator吧,今天我就跟大家一起探讨下CodeSmith Generator 7.0.2的激活,这最新版本破解的难度也是超越以往......具体看这篇日 ...