介绍开源的.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 = new TcpListener(desiredLocalListenIPEndPoint.Address, 0);
                        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
    }
时间: 2024-11-01 23:05:19

介绍开源的.net通信框架NetworkComms框架 源码分析(二十一 )TCPConnectionListener的相关文章

缓存框架OSCache部分源码分析

在并发量比较大的场景,如果采用直接访问数据库的方式,将会对数据库带来巨大的压力,严重的情况下可能会导致数据库不可用状态,并且时间的消耗也是不能容忍的.在这种情况下,一般采用缓存的方式.将经常访问的热点数据提前加载到内存中,这样能够大大降低数据库的压力. OSCache是一个开源的缓存框架,虽然现在已经停止维护了,但是对于OSCache的实现还是值得学习和借鉴的.下面通过OSCache的部分源码分析OSCache的设计思想. 缓存数据结构 通常缓存都是通过<K,V>这种数据结构存储,但缓存都是应

android-----XUtils框架之HttpUtils源码分析

之前我们对Volley框架源码进行了分析,知道了他适用于频繁的网络请求,但是不太适合post较大数据以及文件的上传操作,在项目中为了弥补Volley的这个缺陷,使用了XUtils框架的HttpUtils实现了文件上传的操作,上一篇博客我们通过HttpUtils实现了照片上传的实例,见:android-----基于XUtils客户端以及服务器端实现,当然文件上传的方法类似于照片上传,有时间的话单独写一篇博客介绍,这篇博客我们从源码角度来分析HttpUtils的实现原理,希望对这几天的学习做个总结:

ABP源码分析二十六:核心框架中的一些其他功能

本文是ABP核心项目源码分析的最后一篇,介绍一些前面遗漏的功能 AbpSession AbpSession: 目前这个和CLR的Session没有什么直接的联系.当然可以自定义的去实现IAbpSession使之与CLR的Session关联 IAbpSession:定义如下图中的四个属性. NullAbpSession:IAbpSession的一个缺省实现,给每个属性都给予null值,无实际作用 ClaimsAbpSession:实现了从ClaimsPrincipal/ClaimsIdentity

KopDB 框架学习2——源码分析

我的博客:http://mrfufufu.github.io/ 上次我们主要是对 KopDB 框架的使用进行了分析,它是非常简单有用的.这次主要是对它的源码进行分析,进一步的来了解它的真面目. 点击这里去往 "KopDB 框架学习1--使用" 因为 KopDB 采用的是对象关系映射(ORM)模式,即我们使用的编程语言是面向对象语言,而我们使用的数据库则是关系型数据库,那么将面向对象的语言和面向关系的数据库之间建立一种映射关系,这就是对象关系映射了. 使用 ORM 模式,主要是因为我们平

android-----XUtils框架之BitmapUtils源码分析

上一篇使用XUtils的BitmapUtils实现了一个照片墙的功能,参见:android-----XUtils框架之BitmapUtils加载照片实现,这一篇我们从源码的角度分析下BitmapUtils到底是怎么一个执行流程的: 先来回顾下之前我们使用BitmapUtils的步骤: 很简单,就只有两步: (1)通过BitmapUtils的构造函数创建对象: (2)调用BitmapUtils对象的display方法: 好了,我们先从创建BitmapUtils对象开始分析,很自然想到了Bitmap

首选项框架PreferenceFragment部分源码分析

因为要改一些settings里面的bug以及之前在里面有做过勿扰模式,准备对勿扰模式做一个总结,那先分析一下settings的源码,里面的核心应该就是android3.0 上面的首选项框架PreferenceFragment.因为在3.0之前都是把这些东西放在PreferenceActivity的,但是3.0之后google建议把setting放在PreferenceFragment,但是PreferenceActivity也同时在用的,下面就此总结一下: PreferenceActivity的

thinkphp5 源码分析二 框架引导

框架引导文件源代码 (/thinkphp/start.php) 1. 引入基础文件(/thinkphp/base.php) // 加载基础文件 require __DIR__ . '/base.php'; 基础文件(/thinkphp/base.php) 2. 定义系统常量 1 define('THINK_VERSION', '5.0.9'); 2 define('THINK_START_TIME', microtime(true)); 3 define('THINK_START_MEM', m

Java依赖注入库框架 Dagger的源码分析(一)

1.GeneratedAdapters 对应的注释上面是这么说的: A single point for API used in common by Adapters and Adapter generators 被Adapters以及Adapter的生产者广泛使用 通过代码,可以注意到,这是一个final类,是不允许被重载的. 他的构造函数是一个空的构造函数. 同时带有下面的常量的定义: private static final String SEPARATOR = "$$"; pu

Mahout协同过滤框架Taste的源码分析

推荐过程 主要分成了如下几步来完成推荐1. 输入数据预处理2. 获取评分矩阵3. 计算物品相似度4. 矩阵乘法5. 数据过滤6. 计算推荐 测试数据 user&item 1 2 3 4 5 1 3 3 3 2 0 2 4 4 4 0 0 3 5 5 5 0 3 4 4 4 4 1 4 继续阅读 →

Django框架——CBV及源码分析

CBV (基于类的视图函数) 代码示例: urls.py url(r'^login/',views.MyLogin.as_view()) views.py from django.views import View class MyLogin(View): def get(self,request): print("from MyLogin get方法") return render(request,'login.html') def post(self,request): retur