QT:KeepAliveOption的應用


由於用QTcpSocket寫網絡通訊程序,當正常服務端或者客戶端斷開的時候,我們監測信號即可:Signals:stateChanged(QAbstractSocket::SocketState)。(手動關閉網絡連接,也會檢測到斷開)

 

但是當若是有一端無故突然被拔掉網線,這個信號就檢測不到TcpSocket已經斷開了,而且她仍然是連接狀態。

 

那么我們這個時候就需要考慮到心跳信號了。

 

在Qt中,已經提供了QAbstractSocket::KeepAliveOption

clientSocket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);

 

然后去win7系統注冊表中更改:

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters]

“KeepAliveTime”=1000 (ms,32dword)
“KeepAliveInterval”=1000(ms,32dword)

重啟機器。

測試一下拔掉網線后,是否激活了disconnected信號。我感覺還是花了5s左右,才會檢測到網線斷了。

所以根本方法,還是得用心跳機制

如下內容,總結了3種檢測掉線的機制。

QT:KeepAliveOption的應用 - 柳北風兒 - 柳北風兒~~~~~~~欲宇仙炅

 

 

 

 

轉載:http://www.cnblogs.com/BeginGame/archive/2011/09/24/2189750.html

     用戶異常掉線檢測 
                                 David.Zhu  2005/6/1 
   目前主要有三種方法來實現用戶掉線檢測:SO_KEEPALIVE ,SIO_KEEPALIVE_VALS 和Heart-Beat線程。 
下面我就上面的三種方法來做一下介紹。 
(1)SO_KEEPALIVE 機制 
        這是socket庫提供的功能,設置接口是setsockopt API: 
   BOOL  bSet=TRUE; 
   setsockopt(hSocket,SOL_SOCKET,SO_KEEPALIVE,(const char*)&bSet,sizeof(BOOL));

       根據MSDN的文檔,如果為socket設置了KEEPALIVE選項,TCP/IP棧在檢測到對方掉線后, 
   任何在該socket上進行的調用(發送/接受調用)就會立刻返回,錯誤號是WSAENETRESET ; 
   同時,此后的任何在該socket句柄的調用會立刻失敗,並返回WSAENOTCONN錯誤。

該機制的缺點也很明顯: 
         默認設置是空閑2小時才發送一個“保持存活探測分節”,不能保證實時檢測! 
   當然也可以修改時間間隔參數,但是會影響到所有打開此選項的套接口! 
         關聯了完成端口的socket可能會忽略掉該套接字選項。

(2)SIO_KEEPALIVE_VALS 機制 
         這是從彭博兄那里學到一個機制拉,設置接口是WSAIoctl API: 
     DWORD dwError = 0L ; 
     tcp_keepalive sKA_Settings = {0}, sReturned = {0} ; 
     sKA_Settings.onoff = 1 ; 
  sKA_Settings.keepalivetime = 5500 ; // Keep Alive in 5.5 sec. 
     sKA_Settings.keepaliveinterval = 3000 ; // Resend if No-Reply 
     if (WSAIoctl(skNewConnection, SIO_KEEPALIVE_VALS, &sKA_Settings, 
          sizeof(sKA_Settings), &sReturned, sizeof(sReturned), &dwBytes, 
          NULL, NULL) != 0) 
     { 
           dwError = WSAGetLastError() ; 
     } 
  實現時需要添加tcp_keepalive and SIO_KEEPALIVE_VALS的定義文件MSTCPiP.h 
該選項不同於SO_KEEPALIVE 機制的就是它是針對單個連接的,對系統其他的套接 
     口並不影響。 
        針對完成端口的socket,設置了SIO_KEEPALIVE_VALS后,激活包由TCP STACK來負責。 
     當網絡連接斷開后,TCP STACK並不主動告訴上層的應用程序,但是當下一次RECV或者SEND操作 
     進行后,馬上就會返回錯誤告訴上層這個連接已經斷開了.如果檢測到斷開的時候,在這個連接 
     上有正在PENDING的IO操作,則馬上會失敗返回.

該機制的缺點: 
             不通用啦。MS的API只能用於Windows拉。不過,呵呵用彭博兄的評論就是: 
     優雅一些^_^. 
(3)Heart-Beat線程 
        沒說的。自己寫一個后台線程,實現Heart-Beat包,客戶端受到該包后,立刻返回相應的反饋  包。

    該方法的好處是通用,但缺點就是會改變現有的通訊協議!

有開發網絡應用經歷的人都知道,網絡中的接收和發送數據都是使用WINDOWS中的SOCKET進行實現。但是如果此套接字已經斷開,那發送數據和接收數據的時候就一定會有問題。可是如何判斷這個套接字是否還可以使用呢?

有人一定想到使用Send函數中的返回結果來進行判斷。如果返回的長度和自己發送出去的長度一致,那就說明這個套接字是可用的,否則此套接字一定出現了問題。但是我們並不是無時無刻的發送數據呀。如何解決呢?

其實TCP中已經為我們實現了一個叫做心跳的機制。如果你設置了心跳,那TCP就會在一定的時間(比如你設置的是3秒鍾)內發送你設置的次數的心跳(比如說2次),並且此信息不會影響你自己定義的協議。

在VC中實現心跳的例子很多,可是在DLEPHI中一直沒有相應的代碼。下面我是我使用DELPHI編寫的關於心跳的代碼(以IOCP為例),希望對大家有幫助。

定義心跳常量

const 
  IOC_IN               =$80000000; 
  IOC_VENDOR           =$18000000; 
  IOC_out              =$40000000; 
  SIO_KEEPALIVE_VALS   =IOC_IN or IOC_VENDOR or 4;

var

  inKeepAlive,OutKeepAlive:TTCP_KEEPALIVE;

實現代碼是在Acceptsc:= WSAAccept(Listensc, nil, nil, nil, 0);代碼的后面加入:

      opt:=1; 
      if setsockopt(Acceptsc,SOL_SOCKET,SO_KEEPALIVE,@opt,sizeof(opt))=SOCKET_ERROR then 
      begin 
        closesocket(Acceptsc); 
      end; 
      inKeepAlive.onoff:=1; 
      //設置3秒鍾時間間隔

inKeepAlive.keepalivetime:=3000;

      //設置每3秒中發送1次的心跳 
      inKeepAlive.keepaliveinterval:=1; 
      insize:=sizeof(TTCP_KEEPALIVE); 
      outsize:=sizeof(TTCP_KEEPALIVE); 
      if WSAIoctl(Accept,SIO_KEEPALIVE_VALS,@inKeepAlive,insize,@outKeepAlive,outsize,@outByte,nil,nil)=SOCKET_ERROR then 
      begin 
        closesocket(Acceptsc); 
      end;

如果加入以上的代碼以后,系統會每3秒中加入一次的心跳。並且如果客戶端斷線以后(網線斷),函數GetQueuedCompletionStatus會返回FALSE。

if (GetQueuedCompletionStatus(CompletionPort, BytesTransferred,DWORD(PerHandleData), POverlapped(PerIoData), INFINITE) = False) then 
        begin 
           //在這里處理客戶端斷線信息。

continue; 
        end;

以上就是我使用心跳的方法,此方法我已經在我的網絡游戲中使用。情況穩定!

 

轉自:http://www.lofter.com/tag/qtcpsocket


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM