介绍开源的.net通信框架NetworkComms框架 源码分析(二十 )ConnectionCreate
原文网址: http://www.cnblogs.com/csdev
Networkcomms 是一款C# 语言编写的TCP/UDP通信框架 作者是英国人 以前是收费的 目前作者已经开源 许可是:Apache License v2
开源地址是:https://github.com/MarcFletcher/NetworkComms.Net
public abstract partial class Connection
{
/// <summary>
/// Connection information related to this connection.
/// 连接信息类
/// </summary>
public ConnectionInfo ConnectionInfo { get; protected set; }
/// <summary>
/// A manual reset event which can be used to handle connection setup and establish.
/// 手动类型信号灯 连接创建 Setup
/// </summary>
protected ManualResetEvent connectionSetupWait = new ManualResetEvent(false);
/// <summary>
/// A manual reset event which can be used to handle connection setup and establish.
/// 手动类型信号灯 连接创建 Establish
/// </summary>
protected ManualResetEvent connectionEstablishWait = new ManualResetEvent(false);
/// <summary>
/// A boolean used to signal a connection setup exception.
/// 连接创建异常
/// </summary>
protected bool connectionSetupException = false;
/// <summary>
/// If <see cref="connectionSetupException"/> is true provides additional exception information.
/// 连接创建异常 字符信息
/// </summary>
protected string connectionSetupExceptionStr = "";
/// <summary>
/// Create a new connection object
/// 创建一个新的连接对象
/// </summary>
/// <param name="connectionInfo">连接信息 ConnectionInfo corresponding to the new connection</param>
/// <param name="defaultSendReceiveOptions">收发参数 The SendReceiveOptions which should be used as connection defaults</param>
protected Connection(ConnectionInfo connectionInfo, SendReceiveOptions defaultSendReceiveOptions)
{
//If the application layer protocol is disabled the serialiser must be NullSerializer
//and no data processors are allowed.
//如果应用层协议禁用 序列化必须使用NullSerializer 并且不能使用处理器
if (connectionInfo.ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Disabled)
{
if (defaultSendReceiveOptions.Options.ContainsKey("ReceiveConfirmationRequired"))
throw new ArgumentException("Attempted to create an unmanaged connection when the provided send receive" +
" options specified the ReceiveConfirmationRequired option. Please provide compatible send receive options in order to successfully" +
" instantiate this unmanaged connection.", "defaultSendReceiveOptions");
if (defaultSendReceiveOptions.DataSerializer != DPSManager.GetDataSerializer<NullSerializer>())
throw new ArgumentException("Attempted to create an unmanaged connection when the provided send receive" +
" options serialiser was not NullSerializer. Please provide compatible send receive options in order to successfully" +
" instantiate this unmanaged connection.", "defaultSendReceiveOptions");
)
throw new ArgumentException("Attempted to create an unmanaged connection when the provided send receive" +
" options contains data processors. Data processors may not be used with unmanaged connections." +
" Please provide compatible send receive options in order to successfully instantiate this unmanaged connection.", "defaultSendReceiveOptions");
}
SendTimesMSPerKBCache = new CommsMath();
packetBuilder = new PacketBuilder();
//Initialise the sequence counter using the global value
//Subsequent values on this connection are guaranteed to be sequential
//初始化数据包顺序号 用的是networkcomms静态类中的值
//顺序号不会重复
packetSequenceCounter = Interlocked.Increment(ref NetworkComms.totalPacketSendCount);
ConnectionInfo = connectionInfo;
if (defaultSendReceiveOptions != null)
ConnectionDefaultSendReceiveOptions = defaultSendReceiveOptions;
else
ConnectionDefaultSendReceiveOptions = NetworkComms.DefaultSendReceiveOptions;
//Add any listener specific packet handlers if required
//如果需要添加监听器指定的数据包处理器
if (connectionInfo.ConnectionListener != null)
connectionInfo.ConnectionListener.AddListenerPacketHandlersToConnection(this);
if (NetworkComms.commsShutdown) throw new ConnectionSetupException("Attempting to create new connection after global NetworkComms.Net shutdown has been initiated.");
if (ConnectionInfo.ConnectionType == ConnectionType.Undefined || ConnectionInfo.RemoteEndPoint == null)
throw new ConnectionSetupException("ConnectionType and RemoteEndPoint must be defined within provided ConnectionInfo.");
//If a connection already exists with this info then we can throw an exception here to prevent duplicates
//如果一个相同的连接已经存在 我们抛出异常 防止重复
if (NetworkComms.ConnectionExists(connectionInfo.RemoteEndPoint, connectionInfo.LocalEndPoint, connectionInfo.ConnectionType, connectionInfo.ApplicationLayerProtocol))
throw new ConnectionSetupException("A " + connectionInfo.ConnectionType.ToString() + " connection already exists with info " + connectionInfo);
//We add a reference in the constructor to ensure any duplicate connection problems are picked up here
//添加连接引用到NetworkComms静态类中
NetworkComms.AddConnectionReferenceByRemoteEndPoint(this);
}
/// <summary>
/// Establish this connection
/// 创建连接
/// </summary>
public void EstablishConnection()
{
try
{
bool connectionAlreadyEstablishing = false;
lock (_syncRoot)
{
if (ConnectionInfo.ConnectionState == ConnectionState.Established) return;
else if (ConnectionInfo.ConnectionState == ConnectionState.Shutdown) throw new ConnectionSetupException("Attempting to re-establish a closed connection. Please create a new connection instead.");
else if (ConnectionInfo.ConnectionState == ConnectionState.Establishing)
connectionAlreadyEstablishing = true;
else
ConnectionInfo.NoteStartConnectionEstablish();
}
if (connectionAlreadyEstablishing)
{
if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace("Waiting for connection with " + ConnectionInfo + " to be established.");
if (!WaitForConnectionEstablish(NetworkComms.ConnectionEstablishTimeoutMS))
throw new ConnectionSetupException("Timeout waiting for connection to be successfully established.");
}
else
{
if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace("Establishing new connection with " + ConnectionInfo);
EstablishConnectionSpecific();
if (ConnectionInfo.ConnectionState == ConnectionState.Shutdown) throw new ConnectionSetupException("Connection was closed immediately after handshake. This can occur if a different thread used and subsequently closed this connection.");
//Once the above has been done the last step is to allow other threads to use the connection
//在连接信息类中,标注连接创建完成
ConnectionInfo.NoteCompleteConnectionEstablish();
//Not all connection types will have a known remote network identifier
//所有的连接都有一个网络ID
if (ConnectionInfo.NetworkIdentifier != ShortGuid.Empty)
NetworkComms.AddConnectionReferenceByIdentifier(this);
connectionEstablishWait.Set();
if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... connection successfully established with " + ConnectionInfo);
}
}
catch (SocketException e)
{
//If anything goes wrong we close the connection.
//出现错误 关闭连接
CloseConnection();
throw new ConnectionSetupException(e.ToString());
}
catch (Exception ex)
{
//If anything goes wrong we close the connection.
//出现错误 关闭连接
CloseConnection();
//For some odd reason not all SocketExceptions get caught above, so another check here
//一些偶然的场合中,异常会到达此处
if (ex.GetBaseException().GetType() == typeof(SocketException))
throw new ConnectionSetupException(ex.ToString());
else
throw;
}
}
/// <summary>
/// Any connection type specific establish tasks. Should call at least ConnectionHandshake() or TriggerConnectionEstablishDelegates();
/// 创建连接的抽象类
/// </summary>
protected abstract void EstablishConnectionSpecific();
/// <summary>
/// Performs a connection handshake with the remote end of the connection.
/// Exchanges network identifier and any listener whose IPAddress matches the connection localEndPoint IPAddress.
/// 连接握手 执行一个连接握手同远程的连接
/// 交换网络ID等
///
/// </summary>
protected void ConnectionHandshake()
{
if (ConnectionInfo.ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Disabled)
throw new CommunicationException("Attempted to perform handshake on connection where the application protocol has been disabled.");
//If we are server side and we have just received an incoming connection we need to return a connection identifier
//This id will be used in all future connections from this machine
//如果我们是服务器端 我们接收到进入的连接并返回一个连接ID给他
//这个ID将用于未来所有的本机连接
if (ConnectionInfo.ServerSide)
{
if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Debug("Waiting for client connnectionInfo from " + ConnectionInfo);
//Wait for the client to send its identification
//等待客户端发送它的ID
#if NET2
if (!connectionSetupWait.WaitOne(NetworkComms.ConnectionEstablishTimeoutMS, false))
#else
if (!connectionSetupWait.WaitOne(NetworkComms.ConnectionEstablishTimeoutMS))
#endif
throw new ConnectionSetupException("Timeout waiting for client connectionInfo with " + ConnectionInfo + ". Connection created at " + ConnectionInfo.ConnectionCreationTime.ToString("HH:mm:ss.fff") + ", its now " + DateTime.Now.ToString("HH:mm:ss.f"));
if (connectionSetupException)
{
if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Debug("Connection setup exception. ServerSide with " + ConnectionInfo + ", " + connectionSetupExceptionStr);
throw new ConnectionSetupException("ServerSide. " + connectionSetupExceptionStr);
}
//Trigger the connection establish delegates before replying to the connection establish
//在回复连接创建之前触发连接创建委托
TriggerConnectionEstablishDelegates();
}
else
{
//If we are client side part of the handshake is to inform the server of a potential local listener
//Get a list of existing listeners
//如果我们是握手中的客户端 通知服务器他有了一个潜在的本地听众
List<EndPoint> existingLocalListeners = null;
if (ConnectionInfo.LocalEndPoint is IPEndPoint)
existingLocalListeners = Connection.ExistingLocalListenEndPoints(ConnectionInfo.ConnectionType, ));
#if NET4 || NET35
else if (ConnectionInfo.LocalEndPoint is InTheHand.Net.BluetoothEndPoint)
existingLocalListeners = Connection.ExistingLocalListenEndPoints(ConnectionInfo.ConnectionType, new InTheHand.Net.BluetoothEndPoint(ConnectionInfo.LocalBTEndPoint.Address, ConnectionInfo.LocalBTEndPoint.Service));
#endif
//Check to see if we have a local listener for matching the local endpoint address
//If we are client side we use this local listener in our reply to the server
//检查我们是否有一个本地的监听器来对应本地的端点地址
//如果我们作为客户端,我们可以使用本地监听器来回复服务器端
EndPoint selectedExistingLocalListenerEndPoint = null;
if (existingLocalListeners != null && // If we have a suitable local listener 如果我们有合适的本地监听器
existingLocalListeners.Count > && // If we have a suitable local listener 如果我们有合适的本地监听器
!existingLocalListeners.Contains(ConnectionInfo.RemoteEndPoint)) //If this is not an application loop back connection 如果这不是一个应用的回调连接
selectedExistingLocalListenerEndPoint = (existingLocalListeners.Contains(ConnectionInfo.LocalEndPoint) ? ConnectionInfo.LocalEndPoint : existingLocalListeners[]);
//During this exchange we may note an update local listen port
//我们可以注意到一个更新的本地监听端口
if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Debug("Sending connnectionInfo to " + ConnectionInfo);
//Pull-out the parameters we want to send to the server 找出我们想要发送到服务器的参数
//Doing it here rather than all in the following Send Object line keeps it clearer
EndPoint selectedLocalListenerEndPoint = (selectedExistingLocalListenerEndPoint != null ? selectedExistingLocalListenerEndPoint : ConnectionInfo.LocalEndPoint);
bool connectable = selectedExistingLocalListenerEndPoint != null;
//As the client we initiated the connection we now forward our local node identifier to the server
//If we are listening we include our local listen port as well
//作为客户端我们发送本地ID给服务器
//如果我们监听 我们包含本地监听端口
SendObject(Enum.GetName(typeof(ReservedPacketType), ReservedPacketType.ConnectionSetup), new ConnectionInfo(ConnectionInfo.ConnectionType,
NetworkComms.NetworkIdentifier,
selectedLocalListenerEndPoint,
connectable),
NetworkComms.InternalFixedSendReceiveOptions);
//Wait here for the server end to return its own identifier
//在这里等待服务器端返回其自己的标识符
#if NET2
if (!connectionSetupWait.WaitOne(NetworkComms.ConnectionEstablishTimeoutMS, false))
#else
if (!connectionSetupWait.WaitOne(NetworkComms.ConnectionEstablishTimeoutMS))
#endif
throw new ConnectionSetupException("Timeout waiting for server connnectionInfo from " + ConnectionInfo + ". Connection created at " + ConnectionInfo.ConnectionCreationTime.ToString("HH:mm:ss.fff") + ", its now " + DateTime.Now.ToString("HH:mm:ss.f"));
//If we are client side we can update the localEndPoint for this connection to reflect what the remote end might see if we are also listening
//如果我们是客户端 我们更新本地端点
if (selectedExistingLocalListenerEndPoint != null && selectedExistingLocalListenerEndPoint != ConnectionInfo.LocalEndPoint)
{
//We should now be able to set the connectionInfo localEndPoint
//设置连接信息类的本地端点
NetworkComms.UpdateConnectionReferenceByEndPoint(this, ConnectionInfo.RemoteEndPoint, selectedExistingLocalListenerEndPoint);
ConnectionInfo.UpdateLocalEndPointInfo(selectedExistingLocalListenerEndPoint);
}
if (connectionSetupException)
{
if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Debug("Connection setup exception. ClientSide with " + ConnectionInfo + ", " + connectionSetupExceptionStr);
throw new ConnectionSetupException("ClientSide. " + connectionSetupExceptionStr);
}
//Trigger the connection establish delegates once the server has replied to the connection establish
//如果服务器已经针对连接创建有回复 触发连接创建委托
TriggerConnectionEstablishDelegates();
}
}
/// <summary>
/// Trigger connection establish delegates.
/// 触发连接创建委托
/// </summary>
protected void TriggerConnectionEstablishDelegates()
{
//Call asynchronous connection establish delegates here
//同步调用连接创建委托
if (NetworkComms.globalConnectionEstablishDelegatesAsync != null)
{
NetworkComms.CommsThreadPool.EnqueueItem(QueueItemPriority.Normal, new WaitCallback((obj) =>
{
Connection connectionParam = obj as Connection;
NetworkComms.globalConnectionEstablishDelegatesAsync(connectionParam);
}), this);
}
//Call synchronous connection establish delegates here
//同步调用连接创建委托
if (NetworkComms.globalConnectionEstablishDelegatesSync != null)
NetworkComms.globalConnectionEstablishDelegatesSync(this);
}
/// <summary>
/// Return true if the connection is established within the provided timeout, otherwise false
/// 如果连接在指定的时间内建设完成 返回True
/// </summary>
/// <param name="waitTimeoutMS">超时时间 Wait time in milliseconds before returning</param>
/// <returns>True if the wait was triggered, false otherwise after the provided timeout.</returns>
protected bool WaitForConnectionEstablish(int waitTimeoutMS)
{
if (ConnectionInfo.ConnectionState == ConnectionState.Established)
return true;
else
{
if (NetworkComms.LoggingEnabled)
NetworkComms.Logger.Trace("Waiting for new connection to be successfully established before continuing with " + ConnectionInfo);
if (ConnectionInfo.ConnectionState == ConnectionState.Shutdown)
throw new ConnectionShutdownException("Attempted to wait for connection establish on a connection that is already shutdown.");
#if NET2
return connectionSetupWait.WaitOne(waitTimeoutMS, false);
#else
return connectionSetupWait.WaitOne(waitTimeoutMS);
#endif
}
}
/// <summary>
/// Handle an incoming ConnectionSetup packet type
/// 处理一个连接创建类型的数据包
/// </summary>
/// <param name="packetDataSection">Serialised handshake data</param>
internal void ConnectionSetupHandler(MemoryStream packetDataSection)
{
//We should never be trying to handshake an established connection
//我们不要尝试与已经创建的连接握手
ConnectionInfo remoteConnectionInfo = NetworkComms.InternalFixedSendReceiveOptions.DataSerializer.DeserialiseDataObject<ConnectionInfo>(packetDataSection,
NetworkComms.InternalFixedSendReceiveOptions.DataProcessors, NetworkComms.InternalFixedSendReceiveOptions.Options);
if (ConnectionInfo.ConnectionType != remoteConnectionInfo.ConnectionType)
{
connectionSetupException = true;
connectionSetupExceptionStr = "Remote connectionInfo provided connectionType did not match expected connection type.";
}
else
{
//We use the following bool to track a possible existing connection which needs closing
//我们使用下面的布尔值跟踪一个可能存在的需要关闭的连接
bool possibleClashWithExistingConnection = false;
Connection existingConnection = null;
//We first try to establish everything within this lock in one go
//我们首先尝试在锁的内部解决这个问题
//If we can't quite complete the establish we have to come out of the lock at try to sort the problem
//如果我们不能很好的完成创建工作 我们可能需要到锁外面重新解决这个问题
bool connectionEstablishedSuccess = ConnectionSetupHandlerFinal(remoteConnectionInfo, ref possibleClashWithExistingConnection, ref existingConnection);
//If we were not successful at establishing the connection we need to sort it out!
//如果连接没有成功建立 我们需要解决这个问题
if (!connectionEstablishedSuccess && !connectionSetupException)
{
if (existingConnection == null) throw new Exception("Connection establish issues and existingConnection was left as null.");
if (possibleClashWithExistingConnection)
{
//If we have a clash by endPoint we test the existing connection
//如果我们在此端点遇到冲突 我们将测试已经存在的连接
if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Debug("Existing connection with " + ConnectionInfo + ". Testing existing connection.");
))
{
//If the existing connection comes back as alive we don't allow this one to go any further
//This might happen if two peers try to connect to each other at the same time
//如果连接已经存在 则连接创建异常
connectionSetupException = true;
connectionSetupExceptionStr = " ... existing live connection at provided end point for this connection (" + ConnectionInfo + "), there should be no need for a second.";
}
}
//We only try again if we did not log an exception
//我们再试一次,如果我们没有记录到异常
if (!connectionSetupException)
{
//Once we have tried to sort the problem we can try to finish the establish one last time
//一旦我们尝试解决这个问题 我们可以最后一次尝试去完成连接的创建
connectionEstablishedSuccess = ConnectionSetupHandlerFinal(remoteConnectionInfo, ref possibleClashWithExistingConnection, ref existingConnection);
//If we still failed then that's it for this establish
//尝试依然失败
if (!connectionEstablishedSuccess && !connectionSetupException)
{
connectionSetupException = true;
connectionSetupExceptionStr = "Attempted to establish connection with " + ConnectionInfo + ", but due to an existing connection this was not possible.";
}
}
}
//If we are server side and we receive a successful connection setup we can respond to here
//如果我们是服务器端并且我们收到一个成功的连接设置,我们可以在此处进行回复
if (connectionEstablishedSuccess && ConnectionInfo.ServerSide)
SendObject(Enum.GetName(typeof(ReservedPacketType), ReservedPacketType.ConnectionSetup), new ConnectionInfo(ConnectionInfo.ConnectionType, NetworkComms.NetworkIdentifier, ConnectionInfo.LocalEndPoint, true), NetworkComms.InternalFixedSendReceiveOptions);
}
//Trigger any setup waits
//给予信号 触发任何等待设置
connectionSetupWait.Set();
}
/// <summary>
/// Attempts to complete the connection establish with a minimum of locking to avoid possible deadlocking
/// 试图完成连接的创建使用一个最小所来避免可能的冲突
/// </summary>
/// <param name="remoteConnectionInfo">远端点连接信息对象 <see cref="ConnectionInfo"/> corresponding with remoteEndPoint</param>
/// <param name="possibleClashWithExistingConnection">True if a connection already exists with provided remoteEndPoint</param>
/// <param name="existingConnection">A reference to an existing connection if it exists</param>
/// <returns>True if connection is successfully setup, otherwise false</returns>
private bool ConnectionSetupHandlerFinal(ConnectionInfo remoteConnectionInfo, ref bool possibleClashWithExistingConnection, ref Connection existingConnection)
{
lock (NetworkComms.globalDictAndDelegateLocker)
{
List<Connection> connectionByEndPoint = NetworkComms.GetExistingConnection(ConnectionInfo.RemoteEndPoint, ConnectionInfo.LocalEndPoint, ConnectionInfo.ConnectionType, ConnectionInfo.ApplicationLayerProtocol);
//If we no longer have the original endPoint reference (set in the constructor) then the connection must have been closed already
//如果我们没有原始端点引用 然后连接必须已经被关闭
)
{
connectionSetupException = true;
connectionSetupExceptionStr = "Connection setup received after connection closure with " + ConnectionInfo;
}
else
{
//COMMENT: As of version 3.0.0 we have allowed loop back connections where the identifier is the same
//在3.0版本中 我们允许环回连接标识符是相同的
//We need to check for a possible GUID clash 我们需要检查一个可能的GUID冲突
//Probability of a clash is approx 0.1% if 1E19 connections are maintained simultaneously (This many connections has not be tested ;))
//可能出现冲突 概率为 0.1% 如果同时保持1e19次方 连接
//but hey, we live in a crazy world! 但是,嘿,我们生活在一个疯狂的世界
//if (remoteConnectionInfo.NetworkIdentifier == NetworkComms.NetworkIdentifier)
//{
// connectionSetupException = true;
// connectionSetupExceptionStr = "Remote peer has same network identifier to local, " + remoteConnectionInfo.NetworkIdentifier + ". A real duplication is vanishingly improbable so this exception has probably been thrown because the local and remote application are the same.";
//}
//else
] != this)
{
possibleClashWithExistingConnection = true;
existingConnection = connectionByEndPoint[];
}
].ConnectionInfo.NetworkIdentifier != ShortGuid.Empty &&
connectionByEndPoint[].ConnectionInfo.NetworkIdentifier != remoteConnectionInfo.NetworkIdentifier)
{
//We are in the same connection, so don't need to throw and exception but the remote network identifier
//has changed.
//我们在同一个连接,所以不需要抛弃和异常但远程网络标识符已经改变。
//This can happen for connection types where the local connection (this) may not have been closed
//这可能发生 由于本地连接没有关闭
//when the remote peer closed. We need to trigger the connection close delegates with the old info, update
//the connection info and then call the establish delegates
//远程连接关闭时,我们需要触发连接的关闭委托,更新连接信息 然后调用创建委托
#region Reset Connection without closing
//Call the connection close delegates
try
{
//Almost there
//Last thing is to call any connection specific shutdown delegates
if (ConnectionSpecificShutdownDelegate != null)
{
if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Debug("Triggered connection specific shutdown delegates with " + ConnectionInfo);
ConnectionSpecificShutdownDelegate(this);
}
}
catch (Exception ex)
{
LogTools.LogException(ex, "ConnectionSpecificShutdownDelegateError", "Error while executing connection specific shutdown delegates for " + ConnectionInfo + ". Ensure any shutdown exceptions are caught in your own code.");
}
try
{
//Last but not least we call any global connection shutdown delegates
if (NetworkComms.globalConnectionShutdownDelegates != null)
{
if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Debug("Triggered global shutdown delegates with " + ConnectionInfo);
NetworkComms.globalConnectionShutdownDelegates(this);
}
}
catch (Exception ex)
{
LogTools.LogException(ex, "GlobalConnectionShutdownDelegateError", "Error while executing global connection shutdown delegates for " + ConnectionInfo + ". Ensure any shutdown exceptions are caught in your own code.");
}
EndPoint newRemoteEndPoint;
if (this.ConnectionInfo.RemoteEndPoint.GetType() == typeof(IPEndPoint) &&
remoteConnectionInfo.LocalEndPoint.GetType() == typeof(IPEndPoint))
newRemoteEndPoint = new IPEndPoint(this.ConnectionInfo.RemoteIPEndPoint.Address, remoteConnectionInfo.LocalIPEndPoint.Port);
else
throw new NotImplementedException("ConnectionSetupHandlerFinal not implemented for EndPoints of type " + this.ConnectionInfo.RemoteEndPoint.GetType());
NetworkComms.UpdateConnectionReferenceByEndPoint(this, newRemoteEndPoint, this.ConnectionInfo.LocalEndPoint);
ConnectionInfo.UpdateInfoAfterRemoteHandshake(remoteConnectionInfo, newRemoteEndPoint);
//Trigger the establish delegates
//出发创建委托
TriggerConnectionEstablishDelegates();
#endregion
return true;
}
else
{
//Update the connection info 更新连接信息
//We never change the this.ConnectionInfo.RemoteEndPoint.Address as there might be NAT involved
//我们不修改ConnnectionInfo.远端点 因为可能有NAT的参与
//We may update the port however 更新端口
EndPoint newRemoteEndPoint;
if (this is IPConnection)
newRemoteEndPoint = new IPEndPoint(this.ConnectionInfo.RemoteIPEndPoint.Address, remoteConnectionInfo.LocalIPEndPoint.Port);
#if NET35 || NET4
else if (this is BluetoothConnection)
newRemoteEndPoint = ConnectionInfo.RemoteBTEndPoint;
#endif
else
throw new NotImplementedException("ConnectionSetupHandlerFinal not implemented for EndPoints of type " + this.ConnectionInfo.RemoteEndPoint.GetType());
NetworkComms.UpdateConnectionReferenceByEndPoint(this, newRemoteEndPoint, this.ConnectionInfo.LocalEndPoint);
ConnectionInfo.UpdateInfoAfterRemoteHandshake(remoteConnectionInfo, newRemoteEndPoint);
return true;
}
}
}
return false;
}
/// <summary>
/// Returns ConnectionInfo.ToString
/// 返回连接信息类的相关信息
/// </summary>
/// <returns></returns>
public override string ToString()
{
return ConnectionInfo.ToString();
}
}
介绍开源的.net通信框架NetworkComms框架 源码分析(二十 )ConnectionCreate的更多相关文章
- ABP源码分析二十六:核心框架中的一些其他功能
本文是ABP核心项目源码分析的最后一篇,介绍一些前面遗漏的功能 AbpSession AbpSession: 目前这个和CLR的Session没有什么直接的联系.当然可以自定义的去实现IAbpSess ...
- 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()) #阅读源码: #左侧工程栏--- ...
- ④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 ...
随机推荐
- 扩展GridView控件——为内容项添加拖放及分组功能
引言 相信大家对GridView都不陌生,是非常有用的控件,用于平铺有序的显示多个内容项.打开任何WinRT应用或者是微软合作商的网站,都会在APP中发现GridView的使用.“Tiles”提供了一 ...
- Senparc.Weixin.MP SDK 微信公众平台开发教程(十六):AccessToken自动管理机制
在<Senparc.Weixin.MP SDK 微信公众平台开发教程(八):通用接口说明>中,我介绍了获取AccessToken(通用接口)的方法. 在实际的开发过程中,所有的高级接口都需 ...
- java 堆栈分析3
很多方式,比如jconsole.jvisualvm,或者jstack -as 这样的形式, 都可以看到实时的java堆栈的变化: eden suvirried0 suvirried1 old perg ...
- 使用EntityFramework的烦恼
我有一个应用程序,是实现数据ETL同步的,即把数据从一个db里抽取出来,经过处理后,存储到另一个db里. O/RM采用的是EF db First. 随着项目程序的开发,EF的不足越来越明显. ● 根据 ...
- ios UIView sizeToFit sizeThatFits
UILabel *testLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 50, 0, 0)]; testLabel.backgroundC ...
- Java基础之泛型
泛型: (1)为什么会出现泛型? 因为集合存放的数据类型不固定,故往集合里面存放元素时,存在安全隐患, 如果在定义集合时,可以想定义数组一样指定数据类型,那么就可以解决该类安全问题. JDK1.5后出 ...
- 掌握js模板引擎
最近要做一个小项目,不管是使用angularjs还是reactjs,都觉得大材小用了.其实我可能只需要引入一个jquery,但想到jquery对dom的操作,对于早已习惯了双向绑定模式的我,何尝不是一 ...
- IoC组件Unity再续~根据类型字符串动态生产对象
回到目录 这个根据类型字符串动态去生产一个接口的对象,在实现项目中用途很广,这即省去了配置config文件的麻烦,又使用生产对象变更可配置,你完全可以把这种多态持久化到数据库里或者XML文件里,在使用 ...
- jQuery实现全选、全不选、反选
如图,需要使用jQuery实现全选.全不选.反选功能: 核心代码: 全选 $("#check_all").click(function(){ $("input:check ...
- iOS开发——高级技术OC篇&运行时(Runtime)机制
运行时(Runtime)机制 本文将会以笔者个人的小小研究为例总结一下关于iOS开发中运行时的使用和常用方法的介绍,关于跟多运行时相关技术请查看笔者之前写的运行时高级用法及相关语法或者查看响应官方文档 ...