WindowsSocket心跳實現

來源:互聯網
上載者:User

0   引言 
在採用 TCP串連的 C/S結構的系統中,當通訊的一方正常關閉或退出時,另一方能收到相應的串連
斷開的通知,然後進行必要的處理;但如果任意一方發生所謂的“非優雅斷開”,如:意外崩潰、死機、
拔掉網線或路由器故障時,另一方無法得知 TCP 串連已經失效,除非繼續在此串連上不斷地發送資料,
經過若干時間後導致錯誤返回。但在很多時候,更希望伺服器端和用戶端都能及時有效地檢測到網路連
接的非正常斷開,然後完成一些必要的清理工作並把錯誤報表給使用者。 
如何及時有效地檢測到通訊一方的非正常斷開,採用的方法是通過通訊的一方或雙方發送心跳包來
告訴對方網路通訊是否正常或已斷開。 
1   心跳原理 
在基於電路交換的網路中,有專用的控制信令通道,能夠及時發現通路斷開、故障,而 TCP/IP網路
中,鏈路的連通只在串連雙方選項組,物理通道內不存在一個實際的串連鏈路,通訊的雙方只能定時
發送簡單的資訊給另一方,並根據逾時來判斷線路是長時間空閑還是已斷開。這種通過每隔一定時間發
送一個固定資訊給對方,對方收到後回複一個固定資訊,告訴對方“我還在”的方式非常類似於心跳,所
發送的這種簡單資訊就稱為“心跳包”。 
心跳包的發送,通常有兩種技術:一種是由使用者在應用程式層實現的心跳包,另一種是由 TCP 協議層提
供的 KeepAlive  。  
基於Windows Socket的網路通訊中的心跳機制原理及其實現 
 
18 
2   應用程式層自己實現的心跳包 
由應用程式自己發送心跳包來檢測串連是否正常,大致的方法是:伺服器在一個 Timer 事件中定時
向用戶端發送一個短小精悍的資料包,然後啟動一個低層級的線程,在該線程中不斷檢測用戶端的回應,
如果在一定時間內沒有收到用戶端的回應,即認為用戶端已經掉線;同樣,如果用戶端在一定時間內沒
有收到伺服器的心跳包,則認為串連不可用。 
以下代碼給出在 Delphi 中使用 ServerSocket、ClientSocket 進行網路通訊時,如何在服務端實現應用
層心跳包: 
//定義一個 SocketData 記錄類型,用於儲存用戶端資訊 
Type SocketData = Record 
    IP: string;             //用戶端 IP 
    StartTime: Cardinal;    //每次向用戶端發送心跳包的目前時間 
    IsConnected: Boolean;   //是否正與服務端保持串連 
  end; 
  PSocketData = ^SocketData;  //定義一個指向 SocketData 的指標類型  
 
//儲存用戶端資訊,並建立線程,檢測用戶端是否有回應 
procedure TForm1.ServerSktClientConnect(Sender: TObject; 
  Socket: TCustomWinSocket); 
var P: PSocketData; 
begin 
  New(p); 
  p.IP := Socket.RemoteAddress; 
  p.IsConnected := true; 
  Socket.Data := p;               
  if not Timer1.Enabled then 
  begin 
    MyThread := TCheckTimeOut.Create(ServerSkt, Panel1);  
    Timer1.Enabled := true; 
  end; 
end; 
 
//在定時器的 Timer事件中,每隔 2 秒向所有用戶端發送一次心跳包 
procedure TForm1.Timer1Timer(Sender: TObject); 
var 
  i, ActConns: integer; 
  CSocket: TCustomWinSocket; 
begin 
  ActConns := ServerSkt.Socket.ActiveConnections; 
  caption := '串連數:' + inttostr(ActConns); 
  for i := 0 to pred(ActConns) do       
  begin  
基於Windows Socket的網路通訊中的心跳機制原理及其實現 
 
19 
    CSocket := ServerSkt.Socket.Connections[i]; 
    CSocket.SendText('Msgtest'); 
    if PSocketData(CSocket.Data).IsConnected then 
    begin 
      PSocketData(CSocket.Data).StartTime := GetTickCount; 
      PSocketData(CSocket.Data).IsConnected := false; 
    end; 
  end; 
end; 
 
//如果收到用戶端的特定回應,由表示該客戶處於串連狀態 
procedure TForm1.ServerSktClientRead(Sender: TObject; 
  Socket: TCustomWinSocket); 
var RecTxt: string; 
begin 
  RecTxt := Socket.ReceiveText; 
  if RecTxt = 'OK' then          
  begin 
    PSocketData(Socket.Data).IsConnected := true; 
    Memo1.Lines.Add(RecTxt); 
  end; 
end; 
 
//線程入口,用於檢測用戶端是否在規定時間內向服務端回應 
procedure TCheckTimeOut.Execute; 
begin 
  while true do 
  begin 
    Synchronize(CheckConnect); 
    if terminated then exit; 
  end; 
end; 
 
//檢查所有用戶端,是否在 5 000(ms)內向服務端發送回應資訊 
procedure TCheckTimeOut.CheckConnect; 
var i: integer; 
begin 
  for i := 0 to FServerSocket.Socket.ActiveConnections - 1 do 
    if not PSocketData(FServerSocket.Socket.Connections[i].Data).IsConnected then 
      if (GetTickCount - PSocketData(FServerSocket.Socket.Connections[i].Data)^.StartTime) > 5 000 
then 
      begin  
基於Windows Socket的網路通訊中的心跳機制原理及其實現 
 
20 
        Dispose(PSocketData(FServerSocket.Socket.Connections[i].Data)); 
        FServerSocket.Socket.Connections[i].Close; 
      end; 
end; 
 
對於用戶端而言,只要在收到服務端的心跳包後,簡單地發送一個回應資訊即可,代碼略。 
3  TCP的 KeepAlive  保活機制 
因為要考慮到一個伺服器通常會串連多個用戶端,因此由使用者在應用程式層自己實現心跳包,代碼較多
且稍顯複雜,而利用 TCP/IP 協議層為內建的 KeepAlive 功能來實現心跳功能則簡單得多。 
不論是服務端還是用戶端,一方開啟 KeepAlive功能後,就會自動在規定時間內向對方發送心跳包,
而另一方在收到心跳包後就會自動回複,以告訴對方我仍然線上。 
因為開啟 KeepAlive 功能需要消耗額外的寬頻和流量,所以 TCP 協議層預設並不開啟 KeepAlive 功
能,儘管這微不足道,但在按流量計費的環境下增加了費用,另一方面,KeepAlive 設定不合理時可能會
因為短暫的網路波動而斷開健康的 TCP串連。並且,預設的 KeepAlive逾時需要 7,200,000 MilliSeconds,
即 2 小時,探測次數為 5 次。對於很多服務端應用程式來說,2 小時的空閑時間太長。因此,我們需要手
工開啟 KeepAlive 功能並設定合理的 KeepAlive 參數。 
以下代碼給出在 Delphi 中使用 ServerSocket、ClientSocket 進行網路通訊時,如何在服務端通過添加
KeepAlive 功能來自動實現心跳機制。 
//定義心跳常量 
Const  
  IOC_IN = $80000000; 
  IOC_VENDOR = $18000000; 
  IOC_out = $40000000; 
  SIO_KEEPALIVE_VALS = IOC_IN or IOC_VENDOR or 4; 
  DATA_BUFSIZE = 8192; 
 
//定義 KeepAlive 資料結構 
Type 
  TTCP_KEEPALIVE = packed record 
    onoff: integer; 
    keepalivetime: integer; 
    keepaliveinterval: integer; 
  end; 
 
//  開啟 KeepAlive 保活機制,每隔 3 秒向用戶端發送一次心跳包 
procedure TForm1.ServerSocket1ClientConnect(Sender: TObject; Socket: TCustomWinSocket); 
var 
  opt: integer; 
  klive, outKlive: TTCP_KEEPALIVE; 
begin 
  opt := 1;  

21 
    if setsockopt(Socket.SocketHandle,SOL_SOCKET, SO_KEEPALIVE, @opt, SizeOf(opt)) <> 0 then 
    begin 
      Showmessage('setsockopt KeepAlive Error!'); 
    end; 
    klive.onoff := 1;  
    klive.keepalivetime := 3000; 
    klive.keepaliveinterval := 1; 
if WSAIoctl( Socket.SocketHandle, SIO_KEEPALIVE_VALS, @klive, 
             SizeOf(TTCP_KEEPALIVE), @outKlive, 
             SizeOf(TTCP_KEEPALIVE), @opt,0,nil) = SOCKET_ERROR then 
    begin 
      Showmessage('WSAIoctl KeepAlive Error!'); 
    end; 
end; 
 
其中,Windows Socket API函數 Setsockopt 用於設定套介面的選項,而此處則用來開啟 KeepAlive功
能,WSAIoctl 函數則用於設定 KeepAlive 逾時及心跳包發送次數。 
由於是在 ServerSocket 的 OnClientConnect 事件中使用 Socket 參數來設定每個串連上來的用戶端的
KeepAlive,所以上述代碼同樣支援多客戶串連的情況。 
在開啟了 KeepAlive  後, 一旦用戶端死機、 拔網線等“非優雅”退出, 就會觸發服務端的 OnClientError
事件,然後在此事件中完成必要的“善後”處理工作: 
procedure TForm1.ServerSocket1ClientError(Sender: TObject;Socket: TCustomWinSocket; ErrorEvent: 
TErrorEvent;  var ErrorCode: Integer); 
begin 
  ErrorCode:=0; 
  Showmessage('用戶端 '+Socket.RemoteAddress+'非正常退出,中斷連線'); 
  …………        //“善後”處理工作  
  Socket.Close; 
end; 
4   結束語 
實踐證明,利用 TCP 本身支援的 KeepAlive 功能實現斷線檢測,比使用者自己在應用程式層實現檢測更方
便有效,而且探測時頻寬消耗很小。在沒有資料轉送時依賴 KeepAlive 確保斷線檢測,在傳輸資料時 TCP
會通過逾時判斷是否斷線。 
在網路通訊應用系統開發中,根據實際需要也可以在用戶端開啟 KeepAlive,對服務端的非正常斷開
進行及時有效地檢測。 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.