插座在关闭时可以发送信号吗?
Can a socket send a signal when closing?
我正在编写某种服务器应用程序(C++),它保存了服务器正在与之通信的套接字的文件描述符fd_set,我想知道其中一个何时在另一端关闭\关闭而无需读取/写入它。我经常阻止select()(没有超时),等待我提供它的两个fd_set的读取准备和异常条件。
我开始认为任何在另一侧关闭的套接字都会出现在例外中,但当我继续阅读时,我开始明白情况不一定如此。select() 手册页并没有真正说明正在监视哪些异常除外。此外,据我了解,什么被认为是例外情况从操作系统更改为操作系统(我自己正在使用 Ubnubt 11.10),并且我没有在任何地方找到对套接字被关闭\关闭(在另一侧)作为例外的引用。
另外,socket(7) 手册页提到了套接字可能发送的两种信号:
- SIGPIPE - 在写入关机套接字时发送。
- SIGIO - 发生 I/O 事件时发送。
不幸的是,它没有提到什么构成 I/O 事件,无论如何,关闭可能不会被所有人视为 I/O 事件(我自己就是一个很好的例子)。
所以我要问的是 - 我可以让一个插座在关闭时发送信号或将自身插入 exceptfds 中,或者以其他方式主动提示我吗?
谢谢谢伊
通常,当一个套接字被远程对等体关闭时,它变得可读(出于select()
的目的),当你从中读取时,你会得到零字节。此零字节读取表示另一端正常关闭套接字。这不被视为特殊情况。
在我自己的应用程序中,当我的select()
调用(用于读取事件)返回我的文件描述符时,我调用ioctl()
以查看缓冲区上有多少用于读取的内容。如果字节为零,那么我用它来指示连接已关闭。
开始从堆栈溢出的这个答案编写 linux 套接字时,我实际上发现了这一点
您还可以使用"适配器"将此事件抽象到许多其他事件中。
例如,从我的一个项目中...
#region Copyright
/*
This file came from Managed Media Aggregation, You can always find the latest version @ https://net7mma.codeplex.com/
*/
#endregion
namespace Media.Sockets
{
#region NetworkConnection
/// <summary>
/// Represents a <see cref="Connection"/> specific to the Network.
/// </summary>
public class NetworkConnection : Connection, Common.ISocketReference
{
#region NetworkConnectionState
[System.Flags]
protected enum NetworkConnectionState : long
{
None = 0,
Initialized = 1,
Bound = 2,
Connected = 4,
}
#endregion
#region Fields
/// <summary>
/// Created in <see cref="CreateWaitHandle"/>, Disposed in <see cref="Dispose"/>.
/// </summary>
Common.Extensions.WaitHandle.DisposableWaitHandle WaitHandle;
/// <summary>
/// The date and time when the Connection was started.
/// </summary>
protected System.DateTime LasRemoteConnectionStartedDateTime;
/// <summary>
/// The date and time when the Connection was started.
/// </summary>
protected System.DateTime LastRemoteConnectionCompletedDateTime;
#endregion
#region Properties
/// <summary>
/// Gets the amount of time taken to connect to the <see cref="RemoteEndPoint"/>
/// </summary>
public System.TimeSpan RemoteConnectionTime { get { return LastRemoteConnectionCompletedDateTime - LasRemoteConnectionStartedDateTime; } }
/// <summary>
/// The <see cref="System.Net.NetworkInformation.NetworkInterface"/> assoicated with the NetworkConnection.
/// </summary>
public System.Net.NetworkInformation.NetworkInterface NetworkInterface { get; protected set; }
/// <summary>
/// The <see cref="System.Net.Sockets.Socket"/> assoicated with the NetworkConnection.
/// </summary>
public System.Net.Sockets.Socket ConnectionSocket { get; protected set; }
/// <summary>
/// Indicates if the NetworkConnection has a <see cref="NetworkInterface"/> which is not null.
/// </summary>
public bool HasNetworkInterface { get { return NetworkInterface != null; } }
/// <summary>
/// The <see cref="System.Net.EndPoint"/> from which this NetworkConnection connects to the <see cref="RemoteEndPoint"/>
/// </summary>
public System.Net.EndPoint LocalEndPoint { get; protected set; }
/// <summary>
/// Indicates if this NetworkConnection has a <see cref="LocalEndPoint"/> which is not null.
/// </summary>
public bool HasLocalEndPoint { get { return LocalEndPoint != null; } }
/// <summary>
/// The <see cref="System.Net.EndPoint"/> from which this NetworkConnection is connected to via the <see cref="LocalEndPoint"/>
/// </summary>
public System.Net.EndPoint RemoteEndPoint { get; protected set; }
/// <summary>
/// Indicates if this NetworkConnection has a <see cref="RemoteEndPoint"/> which is not null.
/// </summary>
public bool HasRemoteEndPoint { get { return RemoteEndPoint != null; } }
/// <summary>
/// Indicates the <see cref="NetworkConnectionState"/> assoicated with this NetworkConnection
/// </summary>
protected NetworkConnectionState NetworkConnectionFlags
{
get { return (NetworkConnectionState)Flags; }
set { Flags = (long)value; }
}
#endregion
#region Constructor
public NetworkConnection()
: base() { }
public NetworkConnection(string name, bool shouldDispose)
: base(name, shouldDispose) { }
public NetworkConnection(System.Net.Sockets.Socket existingSocket, bool ownsHandle, bool shouldDispose)
: this("System.Net.Socket-" + ownsHandle.ToString(), shouldDispose)
{
if (existingSocket == null) throw new System.ArgumentNullException("existingSocket");
//Assign the ConnectionSocket
ConnectionSocket = existingSocket;
//Flag Initialized.
FlagInitialized();
//Assign the NetworkInterface
NetworkInterface = Common.Extensions.NetworkInterface.NetworkInterfaceExtensions.GetNetworkInterface(ConnectionSocket);
//Create a WaitHandle
CreateWaitHandle(ConnectionSocket.Handle, ownsHandle);
//Check IsBound
if (ConnectionSocket.IsBound)
{
//Flag Bound.
FlagBound();
//Serialize and Assign LocalEndPoint
LocalEndPoint = existingSocket.LocalEndPoint;
}
//Check Connected
if (ConnectionSocket.Connected)
{
//Sample the clock
LasRemoteConnectionStartedDateTime = System.DateTime.UtcNow;
//Serialize and Assign RemoteEndPoint
RemoteEndPoint = existingSocket.RemoteEndPoint;
//Call Connect to FlagConnected and call base logic.
Connect();
//Sample the clock
LastRemoteConnectionCompletedDateTime = System.DateTime.UtcNow;
}
}
#endregion
#region NetworkChange Event Handlers
void NetworkChange_NetworkAvailabilityChanged(object sender, System.Net.NetworkInformation.NetworkAvailabilityEventArgs e)
{
Refresh();
}
void NetworkChange_NetworkAddressChanged(object sender, System.EventArgs e)
{
Refresh();
}
#endregion
#region Bound
protected void FlagBound()
{
//Indicate Bound
Flags |= (long)NetworkConnectionState.Bound;
}
protected void UnFlagBound()
{
//Indicate not Bound
Flags &= (long)NetworkConnectionState.Bound;
}
#endregion
#region Initialize
protected void FlagInitialized()
{
//Indicate Connected
Flags |= (long)NetworkConnectionState.Initialized;
}
protected void UnFlagInitialized()
{
//Indicate Not Connected
Flags &= (long)NetworkConnectionState.Initialized;
}
public virtual void Initialize(bool registerForEvents)
{
//Check not already Initialized.
if (false == NetworkConnectionFlags.HasFlag(NetworkConnectionState.Initialized))
{
//Indicate Initialized
FlagInitialized();
if (registerForEvents)
{
//Attach events
System.Net.NetworkInformation.NetworkChange.NetworkAddressChanged += NetworkChange_NetworkAddressChanged;
System.Net.NetworkInformation.NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAvailabilityChanged;
}
}
}
#endregion
#region Refresh
public override void Refresh()
{
base.Refresh();
}
#endregion
#region CreateConnectionSocket
public void CreateConnectionSocket(System.Net.Sockets.AddressFamily addressFamily, System.Net.Sockets.SocketType socketType, System.Net.Sockets.ProtocolType protocolType)
{
if (ConnectionSocket == null)
{
ConnectionSocket = new System.Net.Sockets.Socket(addressFamily, socketType, protocolType);
CreateWaitHandle(ConnectionSocket.Handle, true);
}
}
#endregion
#region CreateWaitHandle
public void CreateWaitHandle(System.IntPtr handle, bool ownsHandle)
{
if (WaitHandle == null)
{
WaitHandle = new Common.Extensions.WaitHandle.DisposableWaitHandle(handle, ownsHandle);
}
}
#endregion
#region Connect
protected void FlagConnected()
{
//Indicate Connected
Flags |= (long)NetworkConnectionState.Connected;
}
protected void UnFlagConnected()
{
//Indicate Not Connected
Flags &= (long)NetworkConnectionState.Connected;
}
public override void Connect()
{
//Check not already Connected.
if (false == NetworkConnectionFlags.HasFlag(NetworkConnectionState.Connected))
{
//Check IsEstablished
if (IsEstablished) return;
if (NetworkInterface == null) throw new System.InvalidOperationException("NetworkInterface must be assigned before calling Connect.");
if (LocalEndPoint == null) throw new System.InvalidOperationException("LocalEndPoint must be assigned before calling Connect.");
if (RemoteEndPoint == null) throw new System.InvalidOperationException("RemoteEndPoint must be assigned before calling Connect.");
//Set established
base.Connect();
//Indicate Connected
FlagConnected();
//Refresh the connection
Refresh();
}
}
/// <summary>
/// Creates the <see cref="CreateConnectionSocket"/> using the specified options and connects the socket.
/// Assigns <see cref="LocalEndPoint"/> and <see cref="RemoteEndPoint"/>
/// </summary>
/// <param name="addressFamily"></param>
/// <param name="socketType"></param>
/// <param name="protocolType"></param>
/// <param name="addressList"></param>
/// <param name="port"></param>
public virtual void Connect(System.Net.Sockets.AddressFamily addressFamily, System.Net.Sockets.SocketType socketType, System.Net.Sockets.ProtocolType protocolType, System.Net.IPAddress[] addressList, int port)
{
try
{
//Create the socket
CreateConnectionSocket(addressFamily, socketType, protocolType);
//Sample the clock
LasRemoteConnectionStartedDateTime = System.DateTime.UtcNow;
//Connect the socket
ConnectionSocket.Connect(addressList, port);
//Sample the clock
LastRemoteConnectionCompletedDateTime = System.DateTime.UtcNow;
}
finally
{
//Assign the NetworkInterface
NetworkInterface = Common.Extensions.NetworkInterface.NetworkInterfaceExtensions.GetNetworkInterface(ConnectionSocket);
//Assign the LocalEndPoint
LocalEndPoint = (System.Net.IPEndPoint)ConnectionSocket.LocalEndPoint;
//Assign the RemoteEndPoint
RemoteEndPoint = (System.Net.IPEndPoint)ConnectionSocket.RemoteEndPoint;
//Call Connect to FlagConnected and call base logic.
Connect();
}
}
#endregion
#region Disconnect
public virtual void Disconnect(bool allowReuse = false)
{
//Check not already Connected.
if (((NetworkConnectionState)Flags).HasFlag(NetworkConnectionState.Connected))
{
ConnectionSocket.Disconnect(allowReuse);
base.Disconnect();
UnFlagConnected();
Refresh();
}
}
public override void Disconnect()
{
Disconnect(false);
}
#endregion
#region Dispose
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
using (WaitHandle)
{
System.Net.NetworkInformation.NetworkChange.NetworkAddressChanged -= NetworkChange_NetworkAddressChanged;
System.Net.NetworkInformation.NetworkChange.NetworkAvailabilityChanged -= NetworkChange_NetworkAvailabilityChanged;
ConnectionSocket = null;
LocalEndPoint = RemoteEndPoint = null;
NetworkInterface = null;
}
}
#endregion
System.Collections.Generic.IEnumerable<System.Net.Sockets.Socket> Common.ISocketReference.GetReferencedSockets()
{
yield return ConnectionSocket;
}
}
#endregion
}
如果你需要"连接"基类,你可以引用这个
#region Copyright
/*
This file came from Managed Media Aggregation, You can always find the latest version @ https://net7mma.codeplex.com/
Julius.Friedman@gmail.com / (SR. Software Engineer ASTI Transportation Inc. http://www.asti-trans.com)
* v//
*/
#endregion
namespace Media.Sockets
{
#region Connection
/// <summary>
/// Provides a base class to facilitate the concept of a Connection.
/// </summary>
public abstract class Connection : Common.BaseDisposable
{
#region Statics
/// <summary>
/// A string with the format of:
/// `TypeName Id Flags Name`
/// </summary>
const string FormatString = "{0} {1} ({2}) {3}";
#endregion
#region Properties
/// <summary>
/// The unique identifier assoicated with this instance.
/// </summary>
public readonly System.Guid Id = System.Guid.NewGuid();
/// <summary>
/// The date and time the instance was created.
/// </summary>
public readonly System.DateTime Created = System.DateTime.UtcNow;
/// <summary>
/// The name assigned to this instance.
/// </summary>
public readonly string Name;
/// <summary>
/// Indicates if <see cref="Disconnect"/> will be called when disposing.
/// </summary>
public bool IsPersistent
{
get
{
return ShouldDispose == false;
}
set
{
ShouldDispose = value == false;
}
}
/// <summary>
/// Provided for derived implementations
/// </summary>
protected long Flags { get; set; }
/// <summary>
/// Indicates if the Connection is established.
/// </summary>
public virtual bool IsEstablished { get; protected set; }
/// <summary>
/// The date and time the Connection was established.
/// </summary>
public System.DateTime EstablishedDateTime { get; protected set; }
/// <summary>
/// The amount of time the connection has been established.
/// </summary>
public System.TimeSpan TimeEstablished { get { return IsEstablished ? System.DateTime.UtcNow - EstablishedDateTime : System.TimeSpan.Zero; } }
#endregion
#region Connect
/// <summary>
/// If <see cref="IsDisposed"/> is false, Sets <see cref="IsEstablished"/> to true.
/// </summary>
public virtual void Connect()
{
if (IsDisposed) return;
EstablishedDateTime = System.DateTime.UtcNow;
IsEstablished = true;
}
#endregion
#region Disconnect
/// <summary>
/// If <see cref="IsDisposed"/> is false, Sets <see cref="IsEstablished"/> to false.
/// </summary>
public virtual void Disconnect()
{
if (IsDisposed) return;
IsEstablished = false;
}
#endregion
#region Refresh
/// <summary>
/// Refreshes the details of the Connection.
/// Throws a <see cref="System.ObjectDisposedException"/> if <see cref="IsDisposed"/> is true.
/// </summary>
public virtual void Refresh()
{
CheckDisposed();
}
#endregion
#region Dispose
/// <summary>
/// If <see cref="IsDisposed"/> is True the call returns immediately.
/// Calls <see cref="Disconnect"/> if <see cref="IsPersistent"/> is False and calls <see cref="Common.BaseDisposable.Dispose"/>
/// </summary>
public override void Dispose()
{
if (IsDisposed) return;
if (false == IsPersistent) Disconnect();
base.Dispose();
}
#endregion
#region Constructor
public Connection(string name, bool shouldDispose)
: base(shouldDispose)
{
Name = name;
}
public Connection()
: this(string.Empty, true) { }
#endregion
#region ToString
public override string ToString()
{
return string.Format(FormatString, GetType().Name.ToString(), Id.ToString(), Flags, Name);
}
#endregion
}
#endregion
}
您可以参考此代码作为实现其他类的 IPNetworkConnection 的示例。
#region Copyright
/*
This file came from Managed Media Aggregation, You can always find the latest version @ https://net7mma.codeplex.com/
* v//
*/
#endregion
namespace Media.Sockets
{
#region IPNetworkConnection
/// <summary>
/// Represents a <see cref="NetworkConnection"/> which utilizes the IP Protocol.
/// </summary>
public class IPNetworkConnection : NetworkConnection
{
#region Statics
public static System.Net.NetworkInformation.IPGlobalProperties IPGlobalProperties
{
get { return System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties(); }
}
#region CreateIPHostEntry
public static System.Net.IPHostEntry CreateIPHostEntry(System.Net.IPAddress address, string hostName, params string[] aliases)
{
return CreateIPHostEntry(Common.Extensions.Object.ObjectExtensions.ToArray<System.Net.IPAddress>(address),
hostName,
aliases);
}
public static System.Net.IPHostEntry CreateIPHostEntry(string hostName, params System.Net.IPAddress[] address)
{
return CreateIPHostEntry(address, hostName, null);
}
public static System.Net.IPHostEntry CreateIPHostEntry(System.Net.IPAddress[] addresses, string hostName, params string[] aliases)
{
return new System.Net.IPHostEntry()
{
AddressList = Common.Extensions.Array.ArrayExtensions.IsNullOrEmpty(addresses) ? Common.Extensions.Object.ObjectExtensions.ToArray<System.Net.IPAddress>(System.Net.IPAddress.None) : addresses,
Aliases = Common.Extensions.Array.ArrayExtensions.IsNullOrEmpty(aliases) ? Common.Extensions.Object.ObjectExtensions.ToArray<string>(string.Empty) : aliases,
HostName = hostName ?? string.Empty
};
}
#endregion
#endregion
#region Properties
/// <summary>
/// Gets the <see cref="System.Net.NetworkInformation.IPInterfaceProperties"/> assoicated with the <see cref="NetworkInterface"/>
/// </summary>
public System.Net.NetworkInformation.IPInterfaceProperties IPInterfaceProperties
{
get { return HasNetworkInterface ? NetworkInterface.GetIPProperties() : null; }
}
/// <summary>
/// Indicates if the <see cref="RemoteIPEndPoint"/> has a <see cref="System.Net.NetworkInformation.NetworkInterface"/> on this computer.
/// </summary>
public bool IsLocalConnection { get { return HasRemoteIPEndPoint && Common.Extensions.NetworkInterface.NetworkInterfaceExtensions.GetNetworkInterface(RemoteIPEndPoint) != null; } }
/// <summary>
/// Indicates if the <see cref="RemoteIPEndPoint"/> is from within the same network as this computer.
/// </summary>
public bool IsIntranetConnection
{
get { return false == IsLocalConnection && Common.Extensions.IPAddress.IPAddressExtensions.IsOnIntranet(RemoteIPEndPoint.Address); }
}
#region Local
/// <summary>
/// The <see cref="System.Net.IPHostEntry"/> assoicated with the <see cref="LocalIPEndPoint"/>
/// </summary>
public System.Net.IPHostEntry LocalIPHostEntry { get; protected set; }
/// <summary>
/// Indicates if the <see cref="LocalIPHostEntry"/> is not null.
/// </summary>
public bool HasLocalIPHostEntry { get { return LocalIPHostEntry != null; } }
/// <summary>
/// Gets or sets the <see cref="LocalEndPoint"/>.
///
/// If the <see cref="LocalEndPoint"/> is not a <see cref="System.Net.IPEndPoint"/> a <see cref="System.InvalidOperationException"/> will be thrown.
/// </summary>
public System.Net.IPEndPoint LocalIPEndPoint
{
get { return (System.Net.IPEndPoint)LocalEndPoint; }
set
{
if (false == LocalEndPoint is System.Net.IPEndPoint) throw new System.InvalidOperationException("LocalEndPoint is not a System.Net.IPEndPoint");
LocalEndPoint = value;
}
}
/// <summary>
/// Indicates if the <see cref="LocalIPEndPoint"/> is not null.
/// </summary>
public bool HasLocalIPEndPoint { get { return LocalIPEndPoint != null; } }
#endregion
#region Dhcp
/// <summary>
/// Gets the <see cref="System.Net.NetworkInformation.IPAddressCollection"/> assoicated with the <see cref="IPInterfaceProperties"/>
/// </summary>
public virtual System.Net.NetworkInformation.IPAddressCollection DhcpServerAddresses
{
get
{
return IPInterfaceProperties.DhcpServerAddresses;
}
}
/// <summary>
/// Indicates if the IPNetworkConnection utilized Dhcp
/// </summary>
public bool UsesDhcp
{
get
{
return DhcpServerAddresses.Count > 0; /* && DhcpLeaseLifetime != System.TimeSpan.MinValue;*/
}
}
//Could make a Superset class of to unify paths..
//System.Net.NetworkInformation.IPAddressInformationCollection ipAddressCollection;
/// <summary>
/// If <see cref="UsesDhcp"/> the amount of time of the IPAddress is leased according the <see cref="System.Net.NetworkInformation.IPAddressInformation"/> assoicated with the <see cref="LocalIPEndPoint"/>.
///
/// If the <see cref="LocalIPEndPoint"/> is not found in the leased <see cref="System.Net.NetworkInformation.IPAddressInformation"/> then <see cref="Common.Extensions.TimeSpan.TimeSpanExtensions.InfiniteTimeSpan"/> is returned.
/// </summary>
public System.TimeSpan DhcpLeaseLifetime
{
get
{
//If there is no Dhcp server the DhcpLeaveLifeTime is 0
if (false == UsesDhcp) return System.TimeSpan.Zero;
//Check Multicast if the address IsMulticast
if (Common.Extensions.IPAddress.IPAddressExtensions.IsMulticast(LocalIPEndPoint.Address))
{
System.Net.NetworkInformation.MulticastIPAddressInformationCollection multicastIPAddressInformationCollection = IPInterfaceProperties.MulticastAddresses;
foreach (System.Net.NetworkInformation.MulticastIPAddressInformation multicastIPAddressInformation in multicastIPAddressInformationCollection)
{
if (multicastIPAddressInformation.Address.Equals(LocalIPEndPoint.Address))
{
return System.TimeSpan.FromSeconds(multicastIPAddressInformation.DhcpLeaseLifetime);
}
}
}
else //Check Unicast otherwise
{
System.Net.NetworkInformation.UnicastIPAddressInformationCollection unicastIPAddressInformationCollection = IPInterfaceProperties.UnicastAddresses;
foreach (System.Net.NetworkInformation.UnicastIPAddressInformation unicastIPAddressInformation in unicastIPAddressInformationCollection)
{
if (unicastIPAddressInformation.Address.Equals(LocalIPEndPoint.Address))
{
return System.TimeSpan.FromSeconds(unicastIPAddressInformation.DhcpLeaseLifetime);
}
}
}
//Could not find a an IPAddress which matched the LocalIPEndPoint, indicate infinite timeout.
return Common.Extensions.TimeSpan.TimeSpanExtensions.InfiniteTimeSpan;
}
}
/// <summary>
/// If <see cref="UsesDhcp"/> Gets the number of seconds remaining during which this address is valid.
///
/// If the <see cref="LocalIPEndPoint"/> is not found in the leased <see cref="System.Net.NetworkInformation.IPAddressInformation"/> then <see cref="Common.Extensions.TimeSpan.TimeSpanExtensions.InfiniteTimeSpan"/> is returned.
/// </summary>
public System.TimeSpan DhcpAddressValidLifetime
{
get
{
//If there is no Dhcp server the DhcpLeaveLifeTime is 0
if (false == UsesDhcp) return System.TimeSpan.Zero;
//Check Multicast if the address IsMulticast
if (Common.Extensions.IPAddress.IPAddressExtensions.IsMulticast(LocalIPEndPoint.Address))
{
System.Net.NetworkInformation.MulticastIPAddressInformationCollection multicastIPAddressInformationCollection = IPInterfaceProperties.MulticastAddresses;
foreach (System.Net.NetworkInformation.MulticastIPAddressInformation multicastIPAddressInformation in multicastIPAddressInformationCollection)
{
if (multicastIPAddressInformation.Address.Equals(LocalIPEndPoint.Address))
{
return System.TimeSpan.FromSeconds(multicastIPAddressInformation.AddressValidLifetime);
}
}
}
else //Check Unicast otherwise
{
System.Net.NetworkInformation.UnicastIPAddressInformationCollection unicastIPAddressInformationCollection = IPInterfaceProperties.UnicastAddresses;
foreach (System.Net.NetworkInformation.UnicastIPAddressInformation unicastIPAddressInformation in unicastIPAddressInformationCollection)
{
if (unicastIPAddressInformation.Address.Equals(LocalIPEndPoint.Address))
{
return System.TimeSpan.FromSeconds(unicastIPAddressInformation.AddressValidLifetime);
}
}
}
//Could not find a an IPAddress which matched the LocalIPEndPoint, indicate infinite timeout.
return Common.Extensions.TimeSpan.TimeSpanExtensions.InfiniteTimeSpan;
}
}
/// <summary>
/// If <see cref="UsesDhcp"/> Gets the number of seconds remaining during which this address is the preferred address.
///
/// If the <see cref="LocalIPEndPoint"/> is not found in the leased <see cref="System.Net.NetworkInformation.IPAddressInformation"/> then <see cref="Common.Extensions.TimeSpan.TimeSpanExtensions.InfiniteTimeSpan"/> is returned.
/// </summary>
public System.TimeSpan DhcpAddressPreferredLifetime
{
get
{
//If there is no Dhcp server the DhcpLeaveLifeTime is 0
if (false == UsesDhcp) return System.TimeSpan.Zero;
//Check Multicast if the address IsMulticast
if (Common.Extensions.IPAddress.IPAddressExtensions.IsMulticast(LocalIPEndPoint.Address))
{
System.Net.NetworkInformation.MulticastIPAddressInformationCollection multicastIPAddressInformationCollection = IPInterfaceProperties.MulticastAddresses;
foreach (System.Net.NetworkInformation.MulticastIPAddressInformation multicastIPAddressInformation in multicastIPAddressInformationCollection)
{
if (multicastIPAddressInformation.Address.Equals(LocalIPEndPoint.Address))
{
return System.TimeSpan.FromSeconds(multicastIPAddressInformation.AddressPreferredLifetime);
}
}
}
else //Check Unicast otherwise
{
System.Net.NetworkInformation.UnicastIPAddressInformationCollection unicastIPAddressInformationCollection = IPInterfaceProperties.UnicastAddresses;
foreach (System.Net.NetworkInformation.UnicastIPAddressInformation unicastIPAddressInformation in unicastIPAddressInformationCollection)
{
if (unicastIPAddressInformation.Address.Equals(LocalIPEndPoint.Address))
{
return System.TimeSpan.FromSeconds(unicastIPAddressInformation.AddressPreferredLifetime);
}
}
}
//Could not find a an IPAddress which matched the LocalIPEndPoint, indicate infinite timeout.
return Common.Extensions.TimeSpan.TimeSpanExtensions.InfiniteTimeSpan;
}
}
#endregion
#region Remote
/// <summary>
/// Provides information about the <see cref="RemoteEndPoint"/>.Address
/// </summary>
public System.Net.NetworkInformation.IPAddressInformation RemoteAddressInformation { get; protected set; }
/// <summary>
/// Indicates if the <see cref="RemoteAddressInformation"/> is not null.
/// </summary>
public bool HasRemoteAddressInformation { get { return RemoteAddressInformation != null; } }
/// <summary>
/// The <see cref="System.Net.IPHostEntry"/> assoicated with the <see cref="RemoteIPEndPoint"/>
/// </summary>
public System.Net.IPHostEntry RemoteIPHostEntry { get; protected set; }
/// <summary>
/// Indicates if the <see cref="RemoteIPHostEntry"/> is not null.
/// </summary>
public bool HasRemoteIPHostEntry { get { return RemoteIPHostEntry != null; } }
/// <summary>
/// Gets or sets the <see cref="RemoteEndPoint"/>.
///
/// If the <see cref="RemoteEndPoint"/> is not a <see cref="System.Net.IPEndPoint"/> a <see cref="System.InvalidOperationException"/> will be thrown.
/// </summary>
public System.Net.IPEndPoint RemoteIPEndPoint
{
get { return (System.Net.IPEndPoint)RemoteEndPoint; }
set
{
if (false == RemoteEndPoint is System.Net.IPEndPoint) throw new System.InvalidOperationException("RemoteEndPoint is not a System.Net.IPEndPoint");
RemoteEndPoint = value;
}
}
/// <summary>
/// Indicates if the <see cref="RemoteEndPoint"/> is a <see cref="System.Net.IPEndPoint"/>
/// </summary>
public bool HasRemoteIPEndPoint { get { return RemoteIPEndPoint != null; } }
#endregion
#endregion
#region Constructor
/// <summary>
/// Creates a new NetworkConnection with the given.
/// </summary>
/// <param name="remoteIPHostEntry">given</param>
public IPNetworkConnection(System.Net.IPHostEntry remoteIPHostEntry)
: base()
{
if (remoteIPHostEntry == null) throw new System.ArgumentNullException("remoteIPHostEntry");
RemoteIPHostEntry = remoteIPHostEntry;
}
/// <summary>
/// Creates a new NetworkConnection by resolving the given using <see cref="System.Net.Dns.GetHostEntry"/>
/// </summary>
/// <param name="hostNameOrAddress">given</param>
public IPNetworkConnection(string hostNameOrAddress) :
this(System.Net.Dns.GetHostEntry(hostNameOrAddress))
{
RemoteAddressInformation = new IPAddressInformation(System.Net.IPAddress.None, true, false);
}
/// <summary>
/// Creates a new NetworkConnection and <see cref="new System.Net.IPHostEntry"/> using the given address.
/// </summary>
/// <param name="address">The address</param>
public IPNetworkConnection(System.Net.IPAddress address) :
this(CreateIPHostEntry(string.Empty, address))
{
RemoteAddressInformation = new IPAddressInformation(System.Net.IPAddress.None, false, false);
}
public IPNetworkConnection(System.Uri uri) : this(uri.DnsSafeHost) { }
#endregion
#region Refresh
/// <summary>
/// If <see cref="HasNetworkInterface"/> is True And <see cref="HasLocalIPEndPoint"/> then <see cref="NetworkInterface"/> is updated using <see cref="Common.Extensions.NetworkInterface.NetworkInterfaceExtensions.GetNetworkInterface"/>
/// </summary>
public void RefreshNetworkInterface()
{
if (HasNetworkInterface && HasLocalIPEndPoint)
{
NetworkInterface = Common.Extensions.NetworkInterface.NetworkInterfaceExtensions.GetNetworkInterface(LocalIPEndPoint);
}
}
/// <summary>
/// If <see cref="HasRemoteAddressInformation"/> is True And <see cref="RemoteAddressInformation.IsDnsEligible"/> then the <see cref="RemoteIPHostEntry"/> is updated using <see cref="System.Net.Dns.GetHostEntry"/>
/// </summary>
public void RefreshRemoteIPHostEntry()
{
if (HasRemoteAddressInformation && RemoteAddressInformation.IsDnsEligible)
{
RemoteIPHostEntry = System.Net.Dns.GetHostEntry(RemoteIPEndPoint.Address);
}
}
public override void Refresh()
{
if (IsDisposed) return;
base.Refresh();
RefreshNetworkInterface();
RefreshRemoteIPHostEntry();
}
#endregion
#region Connect
public void Connect(int addressIndex, System.Net.NetworkInformation.NetworkInterface networkInterface, int port = 0)
{
if (ConnectionSocket == null) throw new System.InvalidOperationException("There must be a ConnectionSocket assigned before calling Connect.");
if (addressIndex < 0) throw new System.IndexOutOfRangeException("addressIndex must be > 0 and < HostEntry.AddressList.Length");
if (networkInterface == null) throw new System.ArgumentNullException("networkInterface");
NetworkInterface = networkInterface;
RemoteEndPoint = new System.Net.IPEndPoint(RemoteIPHostEntry.AddressList[addressIndex], port);
Connect();
LocalEndPoint = ConnectionSocket.LocalEndPoint;
RemoteAddressInformation = new IPAddressInformation(RemoteIPEndPoint.Address, RemoteAddressInformation.IsDnsEligible, RemoteAddressInformation.IsTransient);
}
#endregion
#region Dispose
public override void Dispose()
{
base.Dispose();
RemoteIPHostEntry = null;
LocalEndPoint = RemoteEndPoint = null;
NetworkInterface = null;
}
#endregion
}
#endregion
}
这只是许多可能的实现之一,还应该概述如何创建"翻译器"并随后创建"翻译连接"。显然(或不是这样)可以在基类以及接口中概述发送和接收方法,以便在需要时允许跨网络通信。
类"连接"为任何类型的连接定义了合适的基础。"网络连接"增加了对网络的要求,最后是"IPNetworkConnection"来实现IP协议所需的逻辑。这也可以扩展到"TcpNetConnection",然后扩展到"TcpIpNetConnection"或以任何其他所需的方式,例如"SerialConnection"或"EthernetConnection",然后构建一个类来允许跨媒体通信,例如"SerialToEthernetNetConnection"。
例如:
#region Copyright
/*
This file came from Managed Media Aggregation, You can always find the latest version @ https://net7mma.codeplex.com/
Julius.Friedman@gmail.com / (SR. Software Engineer ASTI Transportation Inc. http://www.asti-trans.com)
Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction,
* including without limitation the rights to :
* use,
* copy,
* modify,
* merge,
* publish,
* distribute,
* sublicense,
* and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
*
* JuliusFriedman@gmail.com should be contacted for further details.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
*
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE,
* ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* v//
*/
#endregion
namespace Media.Sockets
{
#region TcpNetworkConnection
public class TcpNetworkConnection : NetworkConnection
{
#region Statics
public static System.Net.NetworkInformation.TcpConnectionInformation[] TcpConnectionInformation
{
get { return IPNetworkConnection.IPGlobalProperties.GetActiveTcpConnections(); }
}
#endregion
public TcpNetworkConnection(string name, bool shouldDispose) : base(name, shouldDispose) { }
}
#endregion
}
#region Copyright
/*
This file came from Managed Media Aggregation, You can always find the latest version @ https://net7mma.codeplex.com/
Julius.Friedman@gmail.com / (SR. Software Engineer ASTI Transportation Inc. http://www.asti-trans.com)
Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction,
* including without limitation the rights to :
* use,
* copy,
* modify,
* merge,
* publish,
* distribute,
* sublicense,
* and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
*
* JuliusFriedman@gmail.com should be contacted for further details.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
*
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE,
* ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* v//
*/
#endregion
namespace Media.Sockets
{
#region TcpNetworkConnection
public class TcpIPNetworkConnection : IPNetworkConnection
{
#region Statics
public static System.Net.NetworkInformation.TcpConnectionInformation[] TcpConnectionInformation
{
get { return IPNetworkConnection.IPGlobalProperties.GetActiveTcpConnections(); }
}
#endregion
public TcpIPNetworkConnection() : base(string.Empty) { }
}
#endregion
}
都是有效的实现,但用途不同。
- Qt VTK交互风格的信号到小部件
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 如何将点击的信号和插槽添加到qt中的自定义按钮中
- 如何在没有信号的情况下从C++执行QML插槽
- 线程之间的布尔停止信号
- 如何在信号处理程序和普通函数中对全局变量进行互斥读写操作
- 当用户在qtablewidget中输入单元格时,如何获得信号?C++
- 有可能在信号处理程序中设置promise吗
- 代码在我的计算机上运行良好,但是在将其提交给coursera时遇到未知的信号11问题
- 在条件变量中触发错误信号的频率是多少
- 在信号处理程序中捕获C++未处理的异常并恢复应用程序
- 调试和自由执行中的信号处理
- 升压信号2将插槽传递到成员功能以断开连接
- C++函数包装器来捕获某些信号
- 如何在qt中将信号和插槽与另一个对象连接 --解决了
- 中止信号来自 C++ 中的中止(3) (SIGABRT)
- Qt将信号与另一个类方法连接
- C++ 信号和插槽不工作:插槽不响应事件
- Coursera :自动评分器的未知信号 11
- 插座在关闭时可以发送信号吗?