UNIX網路程式設計 客戶 伺服器心搏函式

2021-06-20 15:54:40 字數 4214 閱讀 6390

下面是關於回送客戶和伺服器程式開發一些簡單的心搏函式。這些函式可以發現對端主機或到對端的通訊路徑的過早失效。

在給出這些函式之前我們必須提出一些警告。首先,有人會想到使用tcp的

保持存活特性(so_keepalive套接字選項)

來提供這種功能,然而tcp得在連線已經閒置2小時之後才傳送乙個保持存活探測段。意識到這一點以後,他們的下乙個問題是如何把保持存活引數改為乙個小得多的值(往往是在秒鐘的量級),以便更快的檢測到失效。儘管縮短tcp的保持存活定時器引數在許多系統上確實可行,但是這些引數通常是按照核心而不是按照每個套接字維護的,因此

改動他們將影響所有開啟該選項的套接字。另外保持存活選項的用意絕不是這個目的(搞頻率的輪詢)。

其次,兩個端系統之間短暫的連線性丟失並非總是壞事。tcp一開始就設計成能夠對付臨時斷連,而源自berkeley的tcp實現將重傳8-10分鐘才放棄某個連線。較新的ip路由協議能夠發現鏈結的失效,並且有可能在短時間內(譬如在秒鐘量級上)啟用候選的路徑。因此應用程式開發人員必須審查想要引入心搏機制的具體應用,確實在沒有聽到對端應答的持續時間超過5-10s之後終止相應連線是件好事還是壞事。有些應用系統需要這種功能,不過大多數卻並不需要。

我們將使用tcp的緊急模式週期地輪詢對端;在下面的講解中我們假設每1s輪詢一次,若持續5s沒有聽到對端應答則認為對端已不再存活,不過這些值可以由應用程式改動。

在這個例子中,客戶每隔1s向伺服器傳送乙個帶外位元組,伺服器取該位元組將導致它向客戶傳送回乙個帶外位元組。每端都需要知道對端是否不復存在或者不再可達。客戶和伺服器每1s遞增他們的cnt變數一次,每收到乙個帶外位元組又把該變數重置為0。如果該計數器達到5(也就是說本程序已有5s沒有收到來自對端的帶外位元組),那就認定連線失效。當有帶外位元組到達時,客戶和伺服器都是用sigurg訊號得以通知。我們在該圖中間指出:資料,回送資料和帶外位元組都通過單個tcp連線交換。

如下是我們的heatbeat_cli函式設定客戶的心搏特性,其中第二個引數是以秒為單位的輪詢頻率,第三個引數是放棄當前連線之前應該經歷的持續無響應輪詢次數。

[cpp]view plain

copy

print?

#include "unp.h"

/* 給heartbeat_cli的引數的拷貝: 套介面描述字(訊號處理程式需用它來傳送和接收帶外資料),sigalrm的頻率,在客戶認為伺服器或連線死掉之前沒有來子伺服器的響應的sigalrm的總數,總量nprobes記錄從最近一次伺服器應答以來的sigalrm的數目 */

static

intservfd;   

static

intnsec;  

/* #seconds between each alarm */

static

intmaxnprobes;  

/* #probes w/no response before quit */

static

intnprobes;  

/* #probes since last server response */

static

void

sig_urg(

int), sig_alrm(

int);  

void

heartbeat_cli(

intservfd_arg, 

intnsec_arg, 

intmaxnprobes_arg)  

static

void

sig_urg(

intsigno)  

intn;  

char

c;  

if( ( n = recv(servfd, &c, 1, msg_oob) ) 

nprobes = 0;  /* reset counter */

return

;  /* may interrupt client code */

}  static

void

sig_alrm(

intsigno)  

send(servfd, "1"

, 1, msg_oob);  

alarm(nsec);  

return

; /* may interrupt client code */

}  

全域性變數

3-6     前3個變數是heartbeat_cli函式引數的副本:套接字描述符(訊號處理函式用它來傳送和接收帶外資料),sigalrm的頻率,在客戶認為伺服器或連線不復存活之前處理的無伺服器響應的sigalrm總數。變數nprobes計量從收到來自伺服器的最後乙個應答以來處理的sigalrm數目。

heartbeat_cli函式

8-20  heartbeat_cli函式檢查並儲存引數,給sigurg和sigalrm建立訊號處理函式,並把套接字的屬主設定為本程序id。執行alarm以排程第乙個sigalrm.

sigalrm處理函式

33-43   本訊號以恆定的間隔產生。遞增計數器nprobes,如果達到maxnprobes,我們就認定伺服器主機或者已經崩潰,或者不再可達。我們這裡是直接結束客戶程序。作為帶外資料傳送乙個含有字元1的位元組(該值沒有任何隱含意義),再執行alarm排程下乙個sigalrm。

下面是伺服器程式的心搏函式。

[cpp]view plain

copy

print?

#include "unp.h"

static

intservfd;  

static

intnsec;  

/* #seconds between each alarm */

static

intmaxnalarms; 

/* #alarms w/no client probe before quit */

static

intnprobes;  

/* #alarms since last client probe */

static

void

sig_urg(

int), sig_alrm(

int);  

void

heartbeat_serv(

intservfd_arg, 

intnsec_arg, 

intmaxnalarms_arg)  

static

void

sig_urg(

intsigno)  

send(servfd, &c, 1, msg_oob);  /* echo back out-of-hand byte */

nprobes = 0;  /* reset counter */

return

;  /* may interrupt server code */

}  static

void

sig_alrm(

intsigno)  

alarm(nsec);  

return

;   

/* may interrupt server code */

}  

heartbeat_serv函式

7-18    宣告變數,函式heartbeat_serv幾乎與客戶的心搏初始化函式一樣。

sigurg處理函式

19-31   伺服器收到乙個帶外通知後就嘗試讀入相應的帶外位元組。就像客戶一樣,如果該帶外位元組還沒有到達,那也沒有宣告關係。伺服器把讀入的帶外位元組作為帶外資料回送給客戶。注意,如果recv返回ewouldblock錯誤,那麼自動變數c碰巧是什麼就回送什麼。既然我們不把帶外位元組的值用於任何目的,這麼處置就不會有問題。重要的是傳送1位元組的帶外資料本身,而不是該位元組到底是什麼。既然剛收到客戶仍然存活著的通知,我們把nprobes重置為0.

sigalrm處理函式

32-41    遞增nprobes,如果達到由呼叫者指定的maxnalarms值,那就終止伺服器程序,否則排程下乙個sigalrm。

網路程式設計 客戶 伺服器程式設計正規化

迭代tcp伺服器總是在完全處理某個客戶的請求之後才開始下乙個客戶的請求處理。這樣的伺服器實際中比較少見。基於udp的大多伺服器卻是這樣實現。傳統併發伺服器呼叫fork派生乙個子程序來處理每個客戶,這使得伺服器能夠同時為多個客戶服務,每個程序乙個客戶。客戶數目的唯一限制是作業系統對其能夠同時擁有多少子...

UNIX網路程式設計 併發伺服器(多程序)

以下程式的源 均是unix網路程式設計上的例子程式。intro daytimetcpsrv1.c include unp.h include include apueerror.h int main int argc,char argv tcp一般採用併發伺服器。當服務乙個客戶請求可能花費較長時間時...

UNIX網路程式設計 伺服器高效併發模式

半同步 半非同步模式 在併發模式下,同步和非同步的概念與i o同步非同步的概念有所不同,這裡的同步是指程式按照 的順序執行,而非同步指的是程式的執行需要系統事件來驅動,比如訊號 中斷等。非同步執行緒效率高,但編寫相對複雜,難於調式,而同步執行緒剛好相反,邏輯簡單,但效率較差。半同步 半非同步模式結合...