如何在来自相同 class 和其他 class 的不同对象之间传递信息作为 C# 中的事件
How to pass information between different objects from the same class and other classes as events in C#
我画了下面的拓扑结构,其中每个节点都是classSensorNode
的一个对象,蓝色的链接表示每个节点与它的邻居之间的链接,节点周围的圆圈表示传输范围对于每个节点。
接收器也是 class Sink
的对象。
我需要实例化它们之间的消息传递和通信,但我不知道应该使用什么机制在这些对象(传感器节点)之间执行消息传递,其中每个节点都有其唯一的 ID,接收器有一个固定的 ID,在我的代码中为 1因为我只用一个水槽。
以下是class我仍然坚持如何实现发送接收和转发以使这种通信适用于这些不同对象之间的问题...
Class“传感器节点”
namespace CRN_Topology
{
class SensorNode
{
public int snID;
public string snName;
public int snDepth;
public DateTime schedulingTime;
public double holdingTime;
public double energy;
public List<int> queue11 = new List<int>();
public List<DateTime> queue12 = new List<DateTime>();
public List<Packet> queue21 = new List<Packet>();
public List<DateTime> queue22 = new List<DateTime>();
public SensorNode(int id,string name,int depth, double energy)
{
this.snID = id;
this.snName = name;
this.snDepth = depth;
this.energy = energy;
}
public void insertHistoryQueue(int packetID, DateTime receivingTime)
{
queue11.Add(packetID);
queue12.Add(receivingTime);
}
public void insertPriorityQueue(Packet packet, DateTime schedulingTime)
{
queue21.Add(packet);
queue22.Add(schedulingTime);
}
public DateTime schedulingTimeCalculations(double holdingTime, DateTime systemTime)
{
schedulingTime = DateTime.FromOADate(holdingTime).Date + systemTime.TimeOfDay;
return schedulingTime;
}
public double holdingTimeCalculations(double alpha, double depth, double beta)
{
holdingTime = alpha * depth + beta;
return holdingTime;
}
public void receive(Packet packet)
{
}
public void forward(Packet packet, int neighborID)
{
}
public void remove()
{
}
public void sendDirect(int rxID, Packet packet)
{
}
}
}
Class“下沉”
namespace CRN_Topology
{
class Sink
{
public string name;
public int sinkID;
public int sinkX;
public int sinkY;
public List<Packet> queue1 = new List<Packet>();
public List<DateTime> queue2 = new List<DateTime>();
public Sink(string name, int Id , int xLocation, int yLocation)
{
this.name = name;
this.sinkID = Id;
this.sinkX = xLocation;
this.sinkY = yLocation;
}
public void insert(Packet packet, DateTime receivingTime)
{
queue1.Add(packet);
queue2.Add(receivingTime);
}
}
}
任何想法,我需要你的建议和帮助,因为我不知道如何在这些对象(传感器节点)之间以及传感器节点和接收器之间传递信息。在 C# 中负责此应用程序的库是什么?
您可以使用聚合关系来实现您所需要的。假设任何接收器只能连接两个节点,每个接收器 class 必须包含两个类型 SensorNode
的属性。例如:
public class Sink
{
public SensorNode Node1 { get; set; }
public SensorNode Node1 { get; set; }
//...
}
这允许您控制节点之间的关系,因此您可以访问通过接收器连接的每个节点。在此对象上调用方法允许您启动对象之间的交互。顺便说一句,SensorNode class 还可以包含对其所有接收器列表的引用,以便通过它自己的方法与它们进行交互:
public class SensorNode
{
public List<Sink> ConnectedSinks { get; set; }
}
PS:在面向对象语言中使用public字段不是一个很好的主意,所以你最好考虑使用public 属性代替。
您可以使用实际 events. Yet, for this case IObservable and IObserver 似乎可以提供更好的模式。虽然在尝试实现这一点时,我很快就摆脱了这种模式。
以下是我开发的解决方案。我展示的是一个摘要 class Node
,旨在用作 SensorNode
和 Sink
的基础,因为两者都可以接收连接。
编辑 1:或者你可以把它变成自己的东西并使用组合,你可以实现抽象方法 Recieve
来引发自定义事件。
编辑 2:也许 Recieve
方法的东西比 Send
更好?我的意思是,在我的代码中,预期的实现是让它使用 _connections
进行广播或尝试将 Packet
到达其目的地,并进行日志记录和其他任何操作。 我真的不知道这是否是您为 Recieve
方法设计的。
abstract class Node
{
/// <summary>
/// Set of all the ids.
/// </summary>
private static readonly Dictionary<int, object> _nodes;
/// <summary>
/// The Id of the node.
/// </summary>
/// <remarks>Can't change.</remarks>
private readonly int _id;
/// <summary>
/// The connections of the node.
/// </summary>
protected readonly Dictionary<int, Node> _connections;
static Node()
{
_nodes = new Dictionary<int, object>();
}
protected Node(int id)
{
// Try register the Id provided
if (_nodes.ContainsKey(id))
{
// If we fail to add it, it means another Node has the same Id already.
throw new ArgumentException($"The id {id} is already in use", nameof(id));
}
_nodes.Add(id, null);
// Store the Id for future reference
_id = id;
_connections = new Dictionary<int, Node>();
}
~Node()
{
// Try to release the Id
// AppDomain unload could be happening
// Any reference could have been set to null
// Do not start async operations
// Do not throw exceptions
// You may, if you so desire, make Node IDisposable, and dispose including this code
var nodes = _nodes;
if (nodes != null)
{
nodes.Remove(Id);
}
}
/// <summary>
/// The Id of the Node
/// </summary>
public int Id { get => _id; }
/// <summary>
/// Connects nodes, bidirectionally.
/// Connect(x, y) is equivalent to Connect(y, x).
/// </summary>
/// <param name="x">The first node to connect</param>
/// <param name="y">The second node to connect</param>
public static void Connect(Node x, Node y)
{
if (x == null)
{
throw new ArgumentNullException(nameof(x));
}
if (y == null)
{
throw new ArgumentNullException(nameof(y));
}
// Bidirectional
x._connections[y.Id] = y;
y._connections[x.Id] = x;
}
/// <summary>
/// Disconnects nodes, bidirectionally.
/// Disconnect(x, y) is equivalent to Disconnect(y, x).
/// </summary>
/// <param name="x">The first node to connect</param>
/// <param name="y">The second node to connect</param>
public static void Disconnect(Node x, Node y)
{
if (x == null)
{
throw new ArgumentNullException(nameof(x));
}
if (y == null)
{
throw new ArgumentNullException(nameof(y));
}
// Short circuit
if (y._connections.ContainsKey(x.Id) && x._connections.ContainsKey(y.Id))
{
// Bidirectional
x._connections.Remove(y.Id);
y._connections.Remove(x.Id);
}
}
protected abstract void Recieve(Packet value);
}
注意:我没有添加任何东西来阻止 Node
到自身的连接
我已经留下Recieve
摘要给你实现。 Sink
可能只会记录消息,而 SensorNode
将必须检查目的地并转发消息。
要从一个节点向另一个节点发送消息,请使用字段 _connections. The key is the
idof the connected
Node. Thefore, if you want to broadcast, you can iterate over
_connections`。如果你想 运行 它们并行,我在下面有一个线程安全的版本。
我考虑到您可能需要为连接附加信息(例如重量/距离/成本/延迟/延迟)。如果是这种情况,请考虑创建一个 Connection
class 并使 _connections
成为它的字典。它的实用优势是您可以将相同的 Connection
对象添加到两个 Nodes
,然后对它们的更新将对它们可见。 或者只是使用Tuple
或者添加更多词典,随便什么,我不在乎。
我花了一段时间才想出一个好的线程安全实现。如果它使用 Monitor
,它会阻止读取连接字典,你需要这样做才能发送 Pakets,所以这不好。读写锁要好一些,但它可能会导致 Connect
和 Disconnect
方法耗尽。
我想出的是一个很好的旧状态机。我添加了另一本字典来保持状态。使所有字典 ConcurrentDictionary
允许并行操作并能够自动修改状态。
代码如下:
abstract class Node
{
/// <summary>
/// Set of all the ids.
/// </summary>
private static readonly ConcurrentDictionary<int, object> _nodes;
/// <summary>
/// The Id of the node.
/// </summary>
/// <remarks>Can't change.</remarks>
private readonly int _id;
/// <summary>
/// The connections of the node.
/// </summary>
protected readonly ConcurrentDictionary<int, Node> _connections;
/// <summary>
/// Status of the connection for synchronization
/// </summary>
private readonly ConcurrentDictionary<int, int> _connectionStatus;
private const int _connecting = 0;
private const int _connected = _connecting + 1;
private const int _disconnecting = _connected + 1;
static Node()
{
_nodes = new ConcurrentDictionary<int, object>();
}
protected Node(int id)
{
// Try register the Id provided
if (!_nodes.TryAdd(id, null))
{
// If we fail to add it, it means another Node has the same Id already.
throw new ArgumentException($"The id {id} is already in use", nameof(id));
}
// Store the Id for future reference
_id = id;
_connections = new ConcurrentDictionary<int, Node>();
_connectionStatus = new oncurrentDictionary<int, int>();
}
~Node()
{
// Try to release the Id
// AppDomain unload could be happening
// Any reference could have been set to null
// Do not start async operations
// Do not throw exceptions
// You may, if you so desire, make Node IDisposable, and dispose including this code
var nodes = _nodes;
if (nodes != null)
{
nodes.TryRemove(Id, out object waste);
}
}
/// <summary>
/// The Id of the Node
/// </summary>
public int Id { get => _id; }
/// <summary>
/// Connects nodes, bidirectionally.
/// Connect(x, y) is equivalent to Connect(y, x).
/// </summary>
/// <param name="x">The first node to connect</param>
/// <param name="y">The second node to connect</param>
public static bool Connect(Node x, Node y)
{
if (x == null)
{
throw new ArgumentNullException(nameof(x));
}
if (y == null)
{
throw new ArgumentNullException(nameof(y));
}
// Bidirectional
// Take nodes in order of Id, for syncrhonization
var a = x;
var b = y;
if (b.Id < a.Id)
{
a = y;
b = x;
}
if (a._connectionStatus.TryAdd(b.Id, _connecting)
&& b._connectionStatus.TryAdd(a.Id, _connecting))
{
a._connections[b.Id] = b;
b._connections[a.Id] = a;
a._connectionStatus[b.Id] = _connected;
b._connectionStatus[a.Id] = _connected;
return true;
}
return false;
}
/// <summary>
/// Disconnects nodes, bidirectionally.
/// Disconnect(x, y) is equivalent to Disconnect(y, x).
/// </summary>
/// <param name="x">The first node to connect</param>
/// <param name="y">The second node to connect</param>
public static bool Disconnect(Node x, Node y)
{
if (x == null)
{
throw new ArgumentNullException(nameof(x));
}
if (y == null)
{
throw new ArgumentNullException(nameof(y));
}
// Short circuit
if (!y._connections.ContainsKey(x.Id) && !x._connections.ContainsKey(y.Id))
{
return false;
}
// Take nodes in order of Id, for syncrhonization
var a = x;
var b = y;
if (b.Id < a.Id)
{
a = y;
b = x;
}
if (a._connectionStatus.TryUpdate(b.Id, _disconnecting, _connected)
&& b._connectionStatus.TryUpdate(a.Id, _disconnecting, _connected))
{
a._connections.TryRemove(b.Id, out x);
b._connections.TryRemove(a.Id, out y);
int waste;
a._connectionStatus.TryRemove(b.Id, out waste);
b._connectionStatus.TryRemove(a.Id, out waste);
return true;
}
return false;
}
protected abstract void Recieve(Packet value);
}
线程喋喋不休:
Connect
和Disconnect
一定要尽量对同一个订单进行操作,这就是为什么我用Id
下订单的原因。 Connect
和 Disconnect
并发执行可能会导致单向连接。
如果您的线程正在尝试添加相同的连接,则只有一个会成功(由于 TryAdd
)。如果两个线程试图删除同一个连接,则只有一个会成功(由于 TryUpdate
)。如果连接存在,Connect
将失败。如果连接不存在 Disconnect
将失败。
如果 Connect
和 Disconnect
同时发生并且连接存在,Connect
将无法添加它并失败,除非 Disconnect
设法先删除它。如果连接不存在,Disconnect
将失败,除非 Connect
设法首先添加它。
状态_connecting
和_disconnecting
是为了防止Connect
和Disconnect
看到connectin在一个方向存在而在另一个方向不存在的情况。
没有线程需要等待另一个线程完成。并且只读取 _connections
.
时不需要同步
虽然理论上只读取 _connections
的线程可能能够看到连接仅存在于一个方向的情况,但该线程将无法发送 Packet
同时两个方向。因此,从该线程的角度来看,在其尝试发送 Packet
.
之间添加或删除了连接
没有验证连接是否存在的方法,这种方法不可靠,因为一旦线程检查连接是否存在,另一个线程可能会在第一个线程能够使用连接之前删除连接。防止连接被删除不是要求的一部分,但可以将其添加为另一种连接状态。
我画了下面的拓扑结构,其中每个节点都是classSensorNode
的一个对象,蓝色的链接表示每个节点与它的邻居之间的链接,节点周围的圆圈表示传输范围对于每个节点。
接收器也是 class Sink
的对象。
我需要实例化它们之间的消息传递和通信,但我不知道应该使用什么机制在这些对象(传感器节点)之间执行消息传递,其中每个节点都有其唯一的 ID,接收器有一个固定的 ID,在我的代码中为 1因为我只用一个水槽。
以下是class我仍然坚持如何实现发送接收和转发以使这种通信适用于这些不同对象之间的问题...
Class“传感器节点”
namespace CRN_Topology
{
class SensorNode
{
public int snID;
public string snName;
public int snDepth;
public DateTime schedulingTime;
public double holdingTime;
public double energy;
public List<int> queue11 = new List<int>();
public List<DateTime> queue12 = new List<DateTime>();
public List<Packet> queue21 = new List<Packet>();
public List<DateTime> queue22 = new List<DateTime>();
public SensorNode(int id,string name,int depth, double energy)
{
this.snID = id;
this.snName = name;
this.snDepth = depth;
this.energy = energy;
}
public void insertHistoryQueue(int packetID, DateTime receivingTime)
{
queue11.Add(packetID);
queue12.Add(receivingTime);
}
public void insertPriorityQueue(Packet packet, DateTime schedulingTime)
{
queue21.Add(packet);
queue22.Add(schedulingTime);
}
public DateTime schedulingTimeCalculations(double holdingTime, DateTime systemTime)
{
schedulingTime = DateTime.FromOADate(holdingTime).Date + systemTime.TimeOfDay;
return schedulingTime;
}
public double holdingTimeCalculations(double alpha, double depth, double beta)
{
holdingTime = alpha * depth + beta;
return holdingTime;
}
public void receive(Packet packet)
{
}
public void forward(Packet packet, int neighborID)
{
}
public void remove()
{
}
public void sendDirect(int rxID, Packet packet)
{
}
}
}
Class“下沉”
namespace CRN_Topology
{
class Sink
{
public string name;
public int sinkID;
public int sinkX;
public int sinkY;
public List<Packet> queue1 = new List<Packet>();
public List<DateTime> queue2 = new List<DateTime>();
public Sink(string name, int Id , int xLocation, int yLocation)
{
this.name = name;
this.sinkID = Id;
this.sinkX = xLocation;
this.sinkY = yLocation;
}
public void insert(Packet packet, DateTime receivingTime)
{
queue1.Add(packet);
queue2.Add(receivingTime);
}
}
}
任何想法,我需要你的建议和帮助,因为我不知道如何在这些对象(传感器节点)之间以及传感器节点和接收器之间传递信息。在 C# 中负责此应用程序的库是什么?
您可以使用聚合关系来实现您所需要的。假设任何接收器只能连接两个节点,每个接收器 class 必须包含两个类型 SensorNode
的属性。例如:
public class Sink
{
public SensorNode Node1 { get; set; }
public SensorNode Node1 { get; set; }
//...
}
这允许您控制节点之间的关系,因此您可以访问通过接收器连接的每个节点。在此对象上调用方法允许您启动对象之间的交互。顺便说一句,SensorNode class 还可以包含对其所有接收器列表的引用,以便通过它自己的方法与它们进行交互:
public class SensorNode
{
public List<Sink> ConnectedSinks { get; set; }
}
PS:在面向对象语言中使用public字段不是一个很好的主意,所以你最好考虑使用public 属性代替。
您可以使用实际 events. Yet, for this case IObservable and IObserver 似乎可以提供更好的模式。虽然在尝试实现这一点时,我很快就摆脱了这种模式。
以下是我开发的解决方案。我展示的是一个摘要 class Node
,旨在用作 SensorNode
和 Sink
的基础,因为两者都可以接收连接。
编辑 1:或者你可以把它变成自己的东西并使用组合,你可以实现抽象方法 Recieve
来引发自定义事件。
编辑 2:也许 Recieve
方法的东西比 Send
更好?我的意思是,在我的代码中,预期的实现是让它使用 _connections
进行广播或尝试将 Packet
到达其目的地,并进行日志记录和其他任何操作。 我真的不知道这是否是您为 Recieve
方法设计的。
abstract class Node
{
/// <summary>
/// Set of all the ids.
/// </summary>
private static readonly Dictionary<int, object> _nodes;
/// <summary>
/// The Id of the node.
/// </summary>
/// <remarks>Can't change.</remarks>
private readonly int _id;
/// <summary>
/// The connections of the node.
/// </summary>
protected readonly Dictionary<int, Node> _connections;
static Node()
{
_nodes = new Dictionary<int, object>();
}
protected Node(int id)
{
// Try register the Id provided
if (_nodes.ContainsKey(id))
{
// If we fail to add it, it means another Node has the same Id already.
throw new ArgumentException($"The id {id} is already in use", nameof(id));
}
_nodes.Add(id, null);
// Store the Id for future reference
_id = id;
_connections = new Dictionary<int, Node>();
}
~Node()
{
// Try to release the Id
// AppDomain unload could be happening
// Any reference could have been set to null
// Do not start async operations
// Do not throw exceptions
// You may, if you so desire, make Node IDisposable, and dispose including this code
var nodes = _nodes;
if (nodes != null)
{
nodes.Remove(Id);
}
}
/// <summary>
/// The Id of the Node
/// </summary>
public int Id { get => _id; }
/// <summary>
/// Connects nodes, bidirectionally.
/// Connect(x, y) is equivalent to Connect(y, x).
/// </summary>
/// <param name="x">The first node to connect</param>
/// <param name="y">The second node to connect</param>
public static void Connect(Node x, Node y)
{
if (x == null)
{
throw new ArgumentNullException(nameof(x));
}
if (y == null)
{
throw new ArgumentNullException(nameof(y));
}
// Bidirectional
x._connections[y.Id] = y;
y._connections[x.Id] = x;
}
/// <summary>
/// Disconnects nodes, bidirectionally.
/// Disconnect(x, y) is equivalent to Disconnect(y, x).
/// </summary>
/// <param name="x">The first node to connect</param>
/// <param name="y">The second node to connect</param>
public static void Disconnect(Node x, Node y)
{
if (x == null)
{
throw new ArgumentNullException(nameof(x));
}
if (y == null)
{
throw new ArgumentNullException(nameof(y));
}
// Short circuit
if (y._connections.ContainsKey(x.Id) && x._connections.ContainsKey(y.Id))
{
// Bidirectional
x._connections.Remove(y.Id);
y._connections.Remove(x.Id);
}
}
protected abstract void Recieve(Packet value);
}
注意:我没有添加任何东西来阻止 Node
到自身的连接
我已经留下Recieve
摘要给你实现。 Sink
可能只会记录消息,而 SensorNode
将必须检查目的地并转发消息。
要从一个节点向另一个节点发送消息,请使用字段 _connections. The key is the
idof the connected
Node. Thefore, if you want to broadcast, you can iterate over
_connections`。如果你想 运行 它们并行,我在下面有一个线程安全的版本。
我考虑到您可能需要为连接附加信息(例如重量/距离/成本/延迟/延迟)。如果是这种情况,请考虑创建一个 Connection
class 并使 _connections
成为它的字典。它的实用优势是您可以将相同的 Connection
对象添加到两个 Nodes
,然后对它们的更新将对它们可见。 或者只是使用Tuple
或者添加更多词典,随便什么,我不在乎。
我花了一段时间才想出一个好的线程安全实现。如果它使用 Monitor
,它会阻止读取连接字典,你需要这样做才能发送 Pakets,所以这不好。读写锁要好一些,但它可能会导致 Connect
和 Disconnect
方法耗尽。
我想出的是一个很好的旧状态机。我添加了另一本字典来保持状态。使所有字典 ConcurrentDictionary
允许并行操作并能够自动修改状态。
代码如下:
abstract class Node
{
/// <summary>
/// Set of all the ids.
/// </summary>
private static readonly ConcurrentDictionary<int, object> _nodes;
/// <summary>
/// The Id of the node.
/// </summary>
/// <remarks>Can't change.</remarks>
private readonly int _id;
/// <summary>
/// The connections of the node.
/// </summary>
protected readonly ConcurrentDictionary<int, Node> _connections;
/// <summary>
/// Status of the connection for synchronization
/// </summary>
private readonly ConcurrentDictionary<int, int> _connectionStatus;
private const int _connecting = 0;
private const int _connected = _connecting + 1;
private const int _disconnecting = _connected + 1;
static Node()
{
_nodes = new ConcurrentDictionary<int, object>();
}
protected Node(int id)
{
// Try register the Id provided
if (!_nodes.TryAdd(id, null))
{
// If we fail to add it, it means another Node has the same Id already.
throw new ArgumentException($"The id {id} is already in use", nameof(id));
}
// Store the Id for future reference
_id = id;
_connections = new ConcurrentDictionary<int, Node>();
_connectionStatus = new oncurrentDictionary<int, int>();
}
~Node()
{
// Try to release the Id
// AppDomain unload could be happening
// Any reference could have been set to null
// Do not start async operations
// Do not throw exceptions
// You may, if you so desire, make Node IDisposable, and dispose including this code
var nodes = _nodes;
if (nodes != null)
{
nodes.TryRemove(Id, out object waste);
}
}
/// <summary>
/// The Id of the Node
/// </summary>
public int Id { get => _id; }
/// <summary>
/// Connects nodes, bidirectionally.
/// Connect(x, y) is equivalent to Connect(y, x).
/// </summary>
/// <param name="x">The first node to connect</param>
/// <param name="y">The second node to connect</param>
public static bool Connect(Node x, Node y)
{
if (x == null)
{
throw new ArgumentNullException(nameof(x));
}
if (y == null)
{
throw new ArgumentNullException(nameof(y));
}
// Bidirectional
// Take nodes in order of Id, for syncrhonization
var a = x;
var b = y;
if (b.Id < a.Id)
{
a = y;
b = x;
}
if (a._connectionStatus.TryAdd(b.Id, _connecting)
&& b._connectionStatus.TryAdd(a.Id, _connecting))
{
a._connections[b.Id] = b;
b._connections[a.Id] = a;
a._connectionStatus[b.Id] = _connected;
b._connectionStatus[a.Id] = _connected;
return true;
}
return false;
}
/// <summary>
/// Disconnects nodes, bidirectionally.
/// Disconnect(x, y) is equivalent to Disconnect(y, x).
/// </summary>
/// <param name="x">The first node to connect</param>
/// <param name="y">The second node to connect</param>
public static bool Disconnect(Node x, Node y)
{
if (x == null)
{
throw new ArgumentNullException(nameof(x));
}
if (y == null)
{
throw new ArgumentNullException(nameof(y));
}
// Short circuit
if (!y._connections.ContainsKey(x.Id) && !x._connections.ContainsKey(y.Id))
{
return false;
}
// Take nodes in order of Id, for syncrhonization
var a = x;
var b = y;
if (b.Id < a.Id)
{
a = y;
b = x;
}
if (a._connectionStatus.TryUpdate(b.Id, _disconnecting, _connected)
&& b._connectionStatus.TryUpdate(a.Id, _disconnecting, _connected))
{
a._connections.TryRemove(b.Id, out x);
b._connections.TryRemove(a.Id, out y);
int waste;
a._connectionStatus.TryRemove(b.Id, out waste);
b._connectionStatus.TryRemove(a.Id, out waste);
return true;
}
return false;
}
protected abstract void Recieve(Packet value);
}
线程喋喋不休:
Connect
和Disconnect
一定要尽量对同一个订单进行操作,这就是为什么我用Id
下订单的原因。 Connect
和 Disconnect
并发执行可能会导致单向连接。
如果您的线程正在尝试添加相同的连接,则只有一个会成功(由于 TryAdd
)。如果两个线程试图删除同一个连接,则只有一个会成功(由于 TryUpdate
)。如果连接存在,Connect
将失败。如果连接不存在 Disconnect
将失败。
如果 Connect
和 Disconnect
同时发生并且连接存在,Connect
将无法添加它并失败,除非 Disconnect
设法先删除它。如果连接不存在,Disconnect
将失败,除非 Connect
设法首先添加它。
状态_connecting
和_disconnecting
是为了防止Connect
和Disconnect
看到connectin在一个方向存在而在另一个方向不存在的情况。
没有线程需要等待另一个线程完成。并且只读取 _connections
.
虽然理论上只读取 _connections
的线程可能能够看到连接仅存在于一个方向的情况,但该线程将无法发送 Packet
同时两个方向。因此,从该线程的角度来看,在其尝试发送 Packet
.
没有验证连接是否存在的方法,这种方法不可靠,因为一旦线程检查连接是否存在,另一个线程可能会在第一个线程能够使用连接之前删除连接。防止连接被删除不是要求的一部分,但可以将其添加为另一种连接状态。