Socket

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

 }  
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值