2012-03-30 17:05
62人閱讀收藏
舉報目前主要有三種方法來實現使用者掉線檢測: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 = , sreturned = ;
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)
實現時需要新增tcp_keepalive and sio_keepalive_vals的定義檔案mstcpip.h
該選項不同於so_keepalive 機制的就是它是針對單個連線的,對系統其他的套接
口並不影響。
針對完成埠的socket,設定了sio_keepalive_vals後,啟用包由tcp stack來負責。
當網路連線斷開後,tcp stack並不主動告訴上層的應用程式,但是當下一次recv或者send操作
進行後,馬上就會返回錯誤告訴上層這個連線已經斷開了.如果檢測到斷開的時候,在這個連線
上有正在pending的io操作,則馬上會失敗返回.
該機制的缺點:
優雅一些^_^.
(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。
begin
//在這裡處理客戶端斷線資訊。
continue;
end;
以上就是我使用心跳的方法,此方法我已經在我的網路遊戲中使用。情況穩定!
struct tcp_keepalive ;
// new wsaioctl options
#define sio_rcvall _wsaiow(ioc_vendor,1)
#define sio_rcvall_mcast _wsaiow(ioc_vendor,2)
#define sio_rcvall_igmpmcast _wsaiow(ioc_vendor,3)
#define sio_keepalive_vals _wsaiow(ioc_vendor,4)
#define sio_absorb_rtralert _wsaiow(ioc_vendor,5)
#define sio_ucast_if _wsaiow(ioc_vendor,6)
#define sio_limit_broadcasts _wsaiow(ioc_vendor,7)
#define sio_index_bind _wsaiow(ioc_vendor,8)
#define sio_index_mcastif _wsaiow(ioc_vendor,9)
#define sio_index_add_mcast _wsaiow(ioc_vendor,10)
#define sio_index_del_mcast _wsaiow(ioc_vendor,11)
socket使用者異常掉線檢測
socket使用者異常掉線檢測 目前主要有三種方法來實現使用者掉線檢測 so keepalive sio keepalive vals 和heart beat執行緒。下面我就上面的三種方法來做一下介紹。1 so keepalive 機制 這是socket庫提供的功能,設定介面是setsockopt ...
socket選項自帶的TCP異常斷開檢測
tcp異常斷開是指在突然斷電,直接拔網線等等情況下,如果通訊雙方沒有進行資料傳送通訊等處理的時候,無法獲知連線已經斷開的情況.在通常的情況下,為了使得socket通訊不受作業系統的限制,需要自己在應用層實現心跳包機制,來檢查異常斷開的情況,一般的方式就是伺服器在一段時間沒有收到客戶端資料報時,定時發...
socket選項自帶的TCP異常斷開檢測
tcp異常斷開是指在突然斷電,直接拔網線等等情況下,如果通訊雙方沒有進行資料傳送通訊等處理的時候,無法獲知連線已經斷開的情況.在通常的情況下,為了使得socket通訊不受作業系統的限制,需要自己在應用層實現心跳包機制,來檢查異常斷開的情況,一般的方式就是伺服器在一段時間沒有收到客戶端資料報時,定時發...