Socket

    技术2022-05-11  78

    using System;using System.Net;using System.Net.Sockets;using System.Collections;using System.Threading;using System.Runtime.InteropServices;

    namespace SocketComponent{ public delegate void SocketOperation(Socket soSocket); public delegate void SocketCloseOperation(string ip,int port); public delegate void SocketProcessData(StateObject state); /// <summary> /// Summary description for SocketBase. /// </summary> public class SocketBase {      public SocketOperation processAfterAccept;  public SocketOperation processAfterConnect;  public SocketCloseOperation processAfterClose;  public SocketProcessData processAfterReceive;  public SocketOperation processAfterAcceptError;

      public bool isAcceptLoop = false;  private int socketTimeout;    private static Logger logger = new Logger(typeof(SocketBase));    #region public method

      public SocketBase()  {   socketTimeout = SG.SEND_RECEIVE_TIMEOUT;   isAcceptLoop = true;  }

        /// <summary>  /// Socket accept method  /// </summary>  /// <param name="ipAddr">ip address</param>  /// <param name="port">listen port</param>  /// <returns>Socket instance</returns>  public Socket SocketAccept(string ipAddr,int port)  {   string FUN_NAME="SocketAccept: ";      IPAddress ipAddress = null;   IPHostEntry ipHostInfo = null;   try   {    ipHostInfo = Dns.Resolve(Dns.GetHostName());      }   catch(Exception e)   {    logger.Error(FUN_NAME+"get host IPAddress error.",e);     return null;   }

       for (int i=0; i<ipHostInfo.AddressList.Length; i++)    {    ipAddress = ipHostInfo.AddressList[i];     if(ipAddr == null)    {     ipAddr = ipHostInfo.AddressList[i].ToString();     break;    }           if (ipAddr == ipAddress.ToString())     {     break;    }    ipAddress = null;   }   if (ipAddress == null)    {    logger.Error(FUN_NAME+ipAddr+" is not this host's IPAddress.");    return null;   }

       Socket soSocket = null;   IPEndPoint iep ;      try   {    iep= new IPEndPoint(IPAddress.Parse(ipAddr),port);   }   catch(Exception e)   {    logger.Error(FUN_NAME+" create IPEndPoint error.",e);    return null;   }   // socket initialize   try   {    // socket create     soSocket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);    // ip port bind     soSocket.Bind(iep);    // listen queue    soSocket.Listen(1000);     // accept stateobject    //StateObject accObject = new StateObject(soSocket,ipAddr,port);    // accept begin    soSocket.BeginAccept( new AsyncCallback(AcceptCallback),soSocket );        }   catch(Exception e)   {    logger.Warn(FUN_NAME+"error. ",e);    SocketClose(soSocket);    return null;   }   return soSocket;    }

      /// <summary>  /// connect to server method  /// </summary>  /// <param name="ipAddr">remotehost ip address</param>  public Socket SocketConnect(string ipAddr,int port)  {     string FUN_NAME="SocketConnect: ";   //parametar check   if(null == ipAddr || 0 == ipAddr.Length)   {    return null;   }   if(0 > port || 65535 < port)   {    return null;   }         Socket soSocket;   IPEndPoint remoteEP;

       try   {    IPAddress svIP = IPAddress.Parse(ipAddr);    remoteEP    = new IPEndPoint(svIP,port);    soSocket       = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);

        StateObject so = new StateObject(soSocket,ipAddr,port);    soSocket.BeginConnect(remoteEP,new AsyncCallback(ConnectCallback),so);       }   catch(Exception e)   {    logger.Warn(FUN_NAME+"error. ",e);    return null;   }   return soSocket;  }

      /// <summary>  /// Socket Syncronized Send Data method  /// </summary>  /// <param name="client">Socket which connect to server</param>  /// <param name="byData">Data that send to Socket</param>  public void SyncSendData(Socket client,byte[] byData)  {   string FUN_NAME="SyncSendData: ";

       if( null==client )   {    return;   }   if( null==byData || 0>byData.Length )   {    return;   }

       try   {    logger.Debug(FUN_NAME+"begin to send data");

        int bytesSent = client.Send(byData,0,byData.Length,SocketFlags.None);    DateTime sendStartTime = System.DateTime.Now;    if(bytesSent < byData.Length)    {     try     {      do      {       bytesSent+=client.Send(byData,bytesSent,byData.Length-bytesSent,SocketFlags.None);       if(sendStartTime.AddMinutes(socketTimeout) <= System.DateTime.Now)       {        logger.Warn(FUN_NAME+"socket time out.");        break;       }      }while(bytesSent < byData.Length);     }     catch(Exception e)     {      logger.Warn(FUN_NAME+"retry send data error .",e);      SocketClose(client);     }    }       }   catch(Exception e)   {    logger.Warn(FUN_NAME+"error. ",e);         SocketClose(client);   }  }

      /// <summary>  /// Socket Send Data method  /// </summary>  /// <param name="client">Socket which connect to server</param>  /// <param name="byData">Data that send to Socket</param>  public void SendData(Socket client, byte [] byData)   {   string FUN_NAME="SendData: ";

       if( null==client )   {    return;   }   if( null==byData || 0>byData.Length )   {    return;   }

       try   {    StateObject sendState = new StateObject(client,byData);    logger.Debug(FUN_NAME+"begin to send data");    client.BeginSend(byData, 0, byData.Length, 0,new AsyncCallback(SendCallback), sendState);   }   catch(Exception e)   {    logger.Warn(FUN_NAME+"error. ",e);         SocketClose(client);   }  }

      /// <summary>  /// Receive Data From Socket  /// </summary>  public void ReceiveData( StateObject recState)  {   string FUN_NAME="ReceiveData: ";   if( null == recState)   {    return;   }

       try   {    recState.WorkSocket.BeginReceive(recState.DataBuffer,0,recState.DataBuffer.Length,     SocketFlags.None,new AsyncCallback(ReceiveCallback),recState);   }   catch(Exception e)   {    logger.Warn(FUN_NAME+"error. ",e);     SocketClose(recState.WorkSocket);   }  }

      /// <summary>  /// Close Socket connection.  /// </summary>  /// <param name="s">Socket handle</param>  public void SocketClose(Socket s)  {   string FUN_NAME="SocketClose: ";      string IP = "";   int port = 0;   if(null != s)   {    if(s.Connected)    {     try     {      IPEndPoint ipep = (IPEndPoint)s.RemoteEndPoint;      IP = ipep.Address.ToString();      port = ipep.Port;           }     catch{}     try     {      s.Shutdown( SocketShutdown.Both );     }     catch(Exception e)     {      logger.Warn(FUN_NAME+"error. ",e);         }    }    try    {     s.Close();    }    catch(Exception e)    {     logger.Warn(FUN_NAME+"error. ",e);        }        processAfterClose(IP,port);   }  }        #endregion

      #region private method  /// <summary>  /// Async accept thread  /// </summary>  /// <param name="ar"></param>  private void AcceptCallback(IAsyncResult ar)   {      string FUN_NAME="AcceptCallback: ";    Socket svSock = null;   Socket clSock = null;   try    {        svSock = (Socket)ar.AsyncState;        if(null == svSock)    {     return;    }    //get client socket    clSock = svSock.EndAccept(ar);    if(null!=clSock)    {     clSock.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.DontLinger,0);     if(SG.KEEP_ALIVE)     {      SetKeepAlive(clSock,SG.KEEP_ALIVE_TIME,SG.KEEP_ALIVE_INTERVAL);         }     processAfterAccept(clSock);    }    //start to accept next connection request    svSock.BeginAccept( new AsyncCallback(AcceptCallback),svSock );   }   catch(ObjectDisposedException ode)   {        logger.Warn(FUN_NAME+"Server host is shut down.",ode); //socket has been closed     SocketClose(svSock);    SocketClose(clSock);    // restart listen and accept    if(isAcceptLoop)    {     processAfterAcceptError(null);       }   }   catch (Exception e )    {    logger.Warn(FUN_NAME+"error.",e);      SocketClose(svSock);    SocketClose(clSock);    if(isAcceptLoop)    {     processAfterAcceptError(null);    }   }    } 

      /// <summary>  /// Async connect thread  /// </summary>  /// <param name="ar"></param>  private void ConnectCallback(IAsyncResult ar)  {   string FUN_NAME="ConnectCallback: ";   StateObject so = null;    try   {        so = (StateObject)ar.AsyncState;       Socket clSock = so.WorkSocket;    if(null!=clSock)    {     clSock.EndConnect(ar);             clSock.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.DontLinger,0);     if(SG.KEEP_ALIVE)     {      SetKeepAlive(clSock,SG.KEEP_ALIVE_TIME,SG.KEEP_ALIVE_INTERVAL);     }     processAfterConnect(clSock);        }   }   catch (Exception e )    {    if(so!=null)    {     logger.Warn(FUN_NAME + "remote server "+so.svIP+":"+so.svPort+" is not online",e);        }    else    {     logger.Warn(FUN_NAME + "has other error.",e);    }   }     }

        /// <summary>  /// Async send data to socket thread  /// </summary>  /// <param name="ar"></param>  private void SendCallback(IAsyncResult ar)  {   string FUN_NAME="SendCallback: ";   int bytesSent = 0;   StateObject sendState;   Socket sendSocket = null;   try   {    sendState  = (StateObject)ar.AsyncState;    sendSocket = sendState.WorkSocket;

        bytesSent = sendSocket.EndSend(ar);

        DateTime sendStartTime = System.DateTime.Now;    if(bytesSent < sendState.DataBuffer.Length)    {     try     {      do      {       bytesSent+=sendSocket.Send(sendState.DataBuffer,bytesSent,        sendState.DataBuffer.Length-bytesSent,SocketFlags.None);       if(sendStartTime.AddMinutes(socketTimeout) <= System.DateTime.Now)       {        logger.Warn(FUN_NAME+"socket time out.");        break;       }      }while(bytesSent < sendState.DataBuffer.Length);     }     catch(Exception e)     {      logger.Warn(FUN_NAME+"retry send data error .",e);      SocketClose(sendSocket);     }    }        if(sendState.DataBuffer.Length!=bytesSent)    {      logger.Warn("Socket send data failure.Need send bytes is "+sendState.DataBuffer.Length      .ToString()+".Have sent bytes is "+bytesSent.ToString());    }    logger.Debug("Send data :",sendState.DataBuffer);    logger.Debug(FUN_NAME+"end to send data.");   }   catch(ObjectDisposedException ode)   {    logger.Warn(FUN_NAME+"Remote host is shut down.",ode);        SocketClose(sendSocket);       }   catch (Exception e )    {    logger.Warn(FUN_NAME + "error.",e);    SocketClose(sendSocket);   }    }  /// <summary>  /// Async receive data to socket thread  /// </summary>  /// <param name="ar"></param>  private void ReceiveCallback(IAsyncResult ar)  {   string FUN_NAME="ReceiveCallback: ";   int bytesReceive = 0;   StateObject recState;   Socket recSocket=null;   try   {    recState =(StateObject)ar.AsyncState;    recSocket = recState.WorkSocket;

        bytesReceive = recSocket.EndReceive(ar);    if( 0>=bytesReceive)    {     string remoteIP = "";     int remotePort  = 0;     if(recSocket.RemoteEndPoint!=null)     {      IPEndPoint ipep = (IPEndPoint)recSocket.RemoteEndPoint;      remoteIP        = ipep.Address.ToString();      remotePort  = ipep.Port;     }     logger.Warn(FUN_NAME+"Remote host "+remoteIP+":"+remotePort.ToString()+" is shut down.");     //remote host shut down     SocketClose(recSocket);     return;    }        DateTime recStartTime = System.DateTime.Now;    if( bytesReceive < recState.DataBuffer.Length )    {     try     {      do      {       bytesReceive+=recSocket.Receive(recState.DataBuffer,bytesReceive,        recState.DataBuffer.Length-bytesReceive,SocketFlags.None);       if(recStartTime.AddMinutes(socketTimeout) <= System.DateTime.Now)       {        logger.Warn(FUN_NAME+"socket time out.");        break;       }      }      while( bytesReceive < recState.DataBuffer.Length );     }     catch(Exception e)     {      logger.Warn(FUN_NAME+"retry recieve data error .",e);      SocketClose(recSocket);     }    }        if( recState.DataBuffer.Length != bytesReceive)    {     logger.Warn("Socket read failure. Need receive bytes is "+recState.DataBuffer.Length      .ToString()+". Have received bytes is "+bytesReceive.ToString());     SocketClose(recSocket);     return;    }             processAfterReceive(recState);      }   catch (Exception e )    {    logger.Warn(FUN_NAME + "error.",e);    SocketClose(recSocket);   }   }    /// <summary>  /// SetKeepAlive of one socket  /// </summary>  /// <param name="socket">the socket object to SetKeepAlive</param>  /// <param name="KeepAliveTime">SetKeepAliveTime(min)</param>  /// <param name="KeepAliveInterval">SetKeepAliveInterval(s)</param>  private void SetKeepAlive(Socket socket, int KeepAliveTime, int KeepAliveInterval)   {   ulong IOC_IN = 0x80000000  ;   ulong IOC_VENDOR = 0x18000000  ;   ulong SIO_KEEPALIVE_VALS = IOC_IN | IOC_VENDOR | 4;   KeepAliveTime = KeepAliveTime *60*1000; //minute  to millsecond   KeepAliveInterval = KeepAliveInterval*1000; //second to millsecond   /* the native structure   struct tcp_keepalive {   ULONG onoff;   ULONG keepalivetime;   ULONG keepaliveinterval;   };   */    // marshal the equivalent of the native structure into a byte array   uint dummy = 0;   byte[] inOptionValues = new byte[Marshal.SizeOf(dummy) * 3];   BitConverter.GetBytes((uint)1).CopyTo(inOptionValues, 0);   BitConverter.GetBytes((uint)KeepAliveTime).CopyTo(inOptionValues, Marshal.SizeOf(dummy));   BitConverter.GetBytes((uint)KeepAliveInterval).CopyTo(inOptionValues, Marshal.SizeOf(dummy) * 2);       // call WSAIoctl via IOControl   socket.IOControl((int)SIO_KEEPALIVE_VALS, inOptionValues, null);   }  #endregion

     }  }

     


    最新回复(0)