心搏函数
目的是可以发现对端主机或到对端的通信路径的过早失效
在考虑使用心搏函数前, 可能会先考虑到TCP自带的保活特性, 即SO_KEEPALIVE套接字选项. 然而TCP默认需要在闲置2小时后才发送一个保持存活探测段. 意识到如此后, 接下来可能会想着能不能修改这个参数, 使TCP更早的检测失效. 答案是可行的, 大多系统都支持修改此参数. 但是这些参数通常是按照内核而不是按照每个套接字维护的. 因此改动他们将影响所有开启该选项的套接字.
其次, 两个端系统之间短暂的连接丢失并非总是坏事. TCP一开始就设计成能够对付临时断连, Berkeley的TCP实现将重传8~10分钟才放弃某连接
因此开发人员必须审查想要引入心博机制的具体应用, 确定在没有对端应答的持续时间超过5-10秒后终止连接是好事还是坏事, 不过这种功能大多是不需要的
接下来, 我们将使用TCP的紧急模式周期的轮询对端: 下面, 我们假设每1秒轮询一次, 若持续5秒钟没有听到对端应答则认为对端已经不再存活, 当然这些值可以由应用程序改动

---------------------------------------------------------------------------------------------------------------------------------------------------------------
目的是可以发现对端主机或到对端的通信路径的过早失效
在考虑使用心搏函数前, 可能会先考虑到TCP自带的保活特性, 即SO_KEEPALIVE套接字选项. 然而TCP默认需要在闲置2小时后才发送一个保持存活探测段. 意识到如此后, 接下来可能会想着能不能修改这个参数, 使TCP更早的检测失效. 答案是可行的, 大多系统都支持修改此参数. 但是这些参数通常是按照内核而不是按照每个套接字维护的. 因此改动他们将影响所有开启该选项的套接字.
其次, 两个端系统之间短暂的连接丢失并非总是坏事. TCP一开始就设计成能够对付临时断连, Berkeley的TCP实现将重传8~10分钟才放弃某连接
因此开发人员必须审查想要引入心博机制的具体应用, 确定在没有对端应答的持续时间超过5-10秒后终止连接是好事还是坏事, 不过这种功能大多是不需要的
接下来, 我们将使用TCP的紧急模式周期的轮询对端: 下面, 我们假设每1秒轮询一次, 若持续5秒钟没有听到对端应答则认为对端已经不再存活, 当然这些值可以由应用程序改动
//客户端
#include "unp.h"
static int servfd;
static int nsec; //客户发送探测带外数据的间隔(秒)
static int maxnprobes; //达到maxnprobes次未响应, 则判定断开
static int nprobes; //当前有nprobes次未响应
static void sig_urg(int), sig_alrm(int); //对于客户来说, sig_alrm函数用来发送探测数据
void heart_beat_cli(int sfd, int sec, int maxp){
servfd = sfd;
if((nsec = sec) < 1)
nsec = 1;
if((maxnprobes = maxp) < nsec)
maxnprobes = nsec;
nprobes = 0;
signal(SIGURG, sig_urg);
//设置SIGURG信号的接收进程
fcntl(servfd, F_SETOWN, getpid());
signal(SIGALRM, sig_alrm);
alarm(nsec);
}
//在带外数据来时接收它
static void sig_urg(int s){
int n;
char c;
if((n = recv(servfd, &c, 1, MSG_OOB)) < 0){
perror("recv error");
exit(-1);
}
nprobes = 0;
}
static void sig_alrm(int s){
if(++nprobes > maxnprobes){
fprintf(stderr, "server is missing...\n");
exit(-1);
}
send(servfd, "0", 1, MSG_OOB);
alarm(nsec);
}
---------------------------------------------------------------------------------------------------------------------------------------------------------------
//服务端
#include "unp.h"
static int clifd;
static int nsec; //服务器接收探测带外数据的间隔(秒)
static int maxnprobes; //达到maxnprobes次未响应, 则判定断开
static int nprobes; //当前有nprobes次未响应
static void sig_urg(int), sig_alrm(int); //对于服务器来说, sig_alrm函数用来增加nprobes的, 每接收一次带外数据则nprobes减少
void heart_beat_serv(int cfd, int sec, int maxp){
clifd = cfd;
if((nsec = sec) < 1)
nsec = 1;
if((maxnprobes = maxp) < nsec)
maxnprobes = nsec;
nprobes = 0;
signal(SIGURG, sig_urg);
//设置SIGURG信号的接收进程
fcntl(clifd, F_SETOWN, getpid());
signal(SIGALRM, sig_alrm);
alarm(nsec);
}
//在带外数据来时接收它
static void sig_urg(int s){
int n;
char c;
if((n = recv(clifd, &c, 1, MSG_OOB)) < 0){
perror("recv error");
exit(-1);
}
nprobes = 0;
send(clifd, "1", 1, MSG_OOB);
}
static void sig_alrm(int s){
if(++nprobes > maxnprobes){
fprintf(stderr, "server is missing...\n");
exit(-1);
}
alarm(nsec);
}