Clinet端不正常斷線時, Server端竟然不知道

1. TcpClient.Connected: 属性获取截止到最后一次 I/O 操作时的 Client 套接字的连接状态。
2. TcpClient.Client.Connected: 属性获取截止到最后的 I/O 操作时 Socket 的连接状态。Connected 属性的值反映最近操作时的连接状态。 如果您需要确定连接的当前状态,请进行非阻止、零字节的 Send 调用。 如果该调用成功返回或引发 WAEWOULDBLOCK 错误代码 (10035),则该套接字仍然处于连接状态;否则,该套接字不再处于连接状态。(MSDN上还有一段代码)
3. TcpClient.Available: 如果远程主机处于关机状态或关闭了连接,Available 可能会引发 SocketException。
4. TcpClient.Client.Available: 如果远程主机处于关机状态或关闭了连接,则 Available 会引发 SocketException。
5. Socket.Poll:  http://msdn.microsoft.com/zh-cn/library/vstudio/system.net.sockets.socket.poll(v=vs.100).aspx (主要看Mode为SelectRead时Poll的返回值)
6. 有网友提供如下方法:

if (s.Poll(-1, SelectMode.SelectRead))
{
   int nRead = s.Receive();
   if (nRead == 0)
   {
     //socket连接已断开
   }
}
接关闭软件! 不能检测出对方断开连接(tcpClient.Close)!
2. 根据TcpClient.Client.Available后面的说明做验证,发现当对方关闭了连接后获取Available还是不回引发异常!
3. 经测试,上述网友提供的方法倒是可以检测 物理网络不通、对方关闭套接字 !但是网上有人说,即使网络正常nRead也可能为0!这种情况我还没有遇到过
不知道Client端已經不存在了, 笨笨的繼續傳遞資料給Client(是我笨吧…Orz)
當然會導致程式發生Exception……….
Server真的會不知道嗎~~會他當然會知道 但是預設為兩小時後[1]~這早就發生Exception…
經過[1]中發現, 原來可以設定  Keep-Alive來保持Socket長連接, 並且偵測網路異常拋出Exception
當Client端發生不正常斷線時, Server端將會立刻知道~~~
Keep-Alive使用方法寫在Comment裡嚕~ 這裡紀錄一下
 
using  System.Net.Sockets;
using  System.Net;
public  class  ServerSocketObject
{
     public   Socket ClientToServerSocket;
     private  Socket ListenSocket;
     private  IPEndPoint ServerIPEndPoint;
     public  ManualResetEvent BeginAccpetControl= new  ManualResetEvent( false );
     //==========================
     private  Boolean IsBeginAccept =  true  ;
     public  List< byte > Reply_Message =  new  List< byte >();
     public  ServerSocketObject()
     {
         string  LocalIP = Dns.GetHostByName(Dns.GetHostName()).AddressList[0].ToString();
         ServerIPEndPoint =  new  IPEndPoint(IPAddress.Parse(LocalIP), 2266);
         ListenSocket =  new  Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
         ListenSocket.Bind(ServerIPEndPoint);
         ListenSocket.Listen(1);   //ip pool 設為 1
         ListenSocket.IOControl(IOControlCode.KeepAliveValues, KeepAlive(1, 1000, 1000),  null ); 
         //將這個Socket使用<b style="background: rgb(255, 102, 255); color: rgb(0, 0, 0);">keep</b>-alive來保持長連線
         //KeepAlive函數參數說明: onOff:是否開啟<b style="background: rgb(255, 102, 255); color: rgb(0, 0, 0);">Keep</b>-Alive(開 1/ 關 0) ,
         //keepAliveTime:當開啟<b style="background: rgb(255, 102, 255); color: rgb(0, 0, 0);">keep</b>-Alive後經過多久時間(ms)開啟偵測
         //keepAliveInterval: 多久偵測一次(ms)
     }
     private  byte [] KeepAlive( int  onOff,  int  keepAliveTime,  int  keepAliveInterval)
     {
         byte [] buffer =  new  byte [12];
         BitConverter.GetBytes(onOff).CopyTo(buffer, 0);
         BitConverter.GetBytes(keepAliveTime).CopyTo(buffer, 4);
         BitConverter.GetBytes(keepAliveInterval).CopyTo(buffer, 8);
         return  buffer;
     }
     public  void  BeginAccept()
     {
         while  (IsBeginAccept)
         {
             BeginAccpetControl.Reset();
             ListenSocket.BeginAccept( new  AsyncCallback(BeginAcceptCallBack), ListenSocket);
             BeginAccpetControl.WaitOne();  //等待Clinet...
         }
         //===================
     }
     private  void  BeginAcceptCallBack(IAsyncResult state)
     {
         Socket Listener = (Socket)state.AsyncState;
         ClientToServerSocket = Listener.EndAccept(state);  //Client連線成功
         ClientToServerSocket.BeginReceive(buffer, 0, BufferSize, 0,  new  AsyncCallback(ReceivedCallBack), ClientToServerSocket); 
         //連線成功後 開始接收Server所傳遞的資料
         BeginAccpetControl.Set();
     }
     private  void  ReceivedCallBack(IAsyncResult ar)
     {
         Socket state = (Socket)ar.AsyncState;
         if  (state.Connected ==  true )
         {
             try
             {
                 int  bytesRead = state.EndReceive(ar);
                 if  (bytesRead > 0)  //當 bytesRead大於0時表示Server傳遞資料過來 等於0時代表Client"正常"斷線
                 {
                     for  ( int  num = 0; num < bytesRead; num++)
                     {
                         Reply_Message.Add(buffer[num]);  //收集資料
                     }
                     state.BeginReceive(buffer, 0, BufferSize, 0,  new  AsyncCallback(ReceivedCallBack), ClientToServerSocket);
                 }
                 else
                 {
                     //處理Client端"正常"斷線的事件
                 }
             }
             catch  (Exception ee)
             {
                 //這裡就是當設定好<b style="background: rgb(255, 102, 255); color: rgb(0, 0, 0);">Keep</b>-alive後, 假設Clinet端發生"不正常斷線(網路異常)"時, 將會
                 //跑進來這個Exception裡,再加以處理
                 state.Shutdown(SocketShutdown.Both);
                 state.Close();
             }
         }
         else
         {
             IsConntect =  false ;
             state.Close();
         }
     }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值