2012-06-19 46 views
3

我正在写一些服务器应用程序(使用C++),它包含服务器正在与之通信的套接字的文件描述符的fd_set,并且我希望知道它们中的一个何时被关闭\而另一端却没有关闭读\写入它。我经常阻塞select()(没有超时),等待读取准备就绪和我提供的两个fd_set的异常条件。关闭时,套接字是否可以发送信号?

我开始认为任何在另一边被关闭的套接字都会出现在exceptfds中,但是当我阅读时,我明白了事实并非如此。 select() man page没有真正说明除了正在监视的fds之外的异常情况。更进一步,我的理解是什么被视为异常情况changes from OS to OS(我自己也使用Ubnubt 11.10),而我还没有发现任何地方被关闭到插座参考\关闭(在另一侧)作为例外。

此外,socket(7) man page提到了2种情况即一个插座可以发送信号:

  1. SIGPIPE - 发送写入一个关闭套接字时。
  2. SIGIO - 发生I/O事件时发送。

不幸的是,没有提到什么是I/O事件,反正关闭可能不会被大家认为是I/O事件(我自己就是一个很好的例子)。

那么,我问的是 - 我可以做一个插座或者发送信号或者本身插入exceptfds当它被关闭,或积极促使我在一些其他的方式?

感谢, 吉文

回答

2

通常,当插座被远程对等关闭时,它变得可读(为select()的目的),而当你从中读取你字节回。该零字节读取指示另一端正常关闭套接字。这不被视为特殊情况。

+0

在“通常”中,是指执行依赖,还是进行正确的关闭/关闭调用?因为我特别想在客户端应用程序未正常关闭时终止提示。在程序突然终止时套接字关闭是否与显式系统调用相同? – ShayPal5

+0

我的意思是“通常”是指远程对等设备正常关机的意义。我用过的每个Berkeley套接字实现都采用相同的方式。导致异常关闭的一种方法是关闭套接字,同时仍然有数据留在缓冲区中读取。取决于许多因素,您可能或可能无法依赖套接字层来确定客户端是否被终止。使用应用程序级别的消息可能会更好(例如,类似于SMTP“QUIT”命令)。 –

+0

谢谢!进一步的研究表明,我使用的套接字实现的行为也是这样,所以我现在可以指望在readfds中弹出的封闭套接字。你的回答真的帮了我很大的忙! – ShayPal5

2

在我自己的应用程序中,当我的select()调用(用于读取事件)在我的文件描述符上返回时,我调用ioctl()来查看缓冲区中有多少位用于读取。如果有零字节,那么我用它来表示连接已关闭。

我居然发现了这一点,当我开始从这个答案here at stack overflow

+0

为什么不直接使用'recv()'的返回值,因为无论如何你需要调用它?这是少一个内核调用。 –

+0

@GregHewgill你在这里说得很好。当我第一次启动linux套接字时,我在这里阅读了这个答案,并且认为这是最好的做法。我不会删除这个答案,因为OP实际上指定他想在没有读/写套接字的情况下检测它。就个人而言,虽然我会改变我的代码,以明天上午你如何建议它,因为它更有意义。感谢那。 – mathematician1975

+0

嗯。那么,整个问题是,我不确定封闭套接字是否会在readfs上出现。如果他们这样做,我会读它们,然后当我从recv()返回-1时关闭它们。在我的问题中,我的意思是我不想循环遍历整套套接字,并且主动读取没有提示为已准备好的套接字,只是为了确保它们在没有通知我的情况下不会关闭(注销我的服务器)。 – ShayPal5

0

写的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/ 

[email protected]/(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 
} 
0

您可以参考这个代码的一个例子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 
} 
0

这只是许多可能的实现方式之一,也应该制定一个如何建立一个“翻译”,然后一个“TranslatedConnection”。显然(或不这样),可以在基类和接口内概述发送和接收方法,以允许跨网络通信(如果需要的话)。

类'连接'为任何类型的连接定义了一个合适的基础。 'NetworkConnection'增加了对网络的要求,最后是'IPNetworkConnection'来实现IP协议所需的逻辑。这也可以扩展到'TcpNetworkConnection',然后扩展到'TcpIpNetworkConnection',或者以任何其他想要的方式,例如'SerialConnection'或'EthernetConnection',然后建立一个类以允许跨媒体通信。 'SerialToEthernetNetworkConnection'等。

例如:

#region Copyright 
/* 
This file came from Managed Media Aggregation, You can always find the latest version @ https://net7mma.codeplex.com/ 

[email protected]/(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: 
* 
* 
* [email protected] 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/ 

[email protected]/(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: 
* 
* 
* [email protected] 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 
} 

都是有效的实现,但用于不同的目的。

相关问题