linux下客户端检测服务器的 heartbeat
来源:互联网 发布:淘宝代购nike 编辑:程序博客网 时间:2024/06/06 01:00
对于heartbeat检测,常用的是在通迅协议上面做,比如pgpool,一台机器会定时向另一台新建一个联接,写和读一些特定字符,之后关闭这个检测用的连接,能连上表明对方没有挂机
对于通过TCP/IP本身这样做,网上win平台下面的例子比较多,相对Linux,MS确实增加了一些特定的函数来检测状态,LINUX下面就没有特定的函数这样做了
下面这部分代码就是通过TCP/IP本身客户端检测服务器是否挂掉,挂掉的意义就是拔网线或断电,测试时要在两台不同的机器上,或是两台虚拟机上,同一台的话,测不出来
代码目的是 使用TCP/IP本身 SO_KEEPALIVE 来检测,不需要辅助协议的支持 当服务器意外挂掉后,客户端能检测出来
代码是演示原理用的,实际使用请自已封装,
主要参考了
http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/
http://hi.baidu.com/zhihui3409/blog/item/cf5344ce15798d0693457e5d.html
http://blog.csdn.net/xioahw/archive/2009/04/08/4056514.aspx
http://blog.csdn.net/woodstar123/archive/2008/11/03/3208432.aspx
服务器端代码,这个没什么可说的
- #include<stdio.h>
- #include<stdlib.h>
- #include<sys/socket.h>
- #include<error.h>
- #include<string.h>
- #include<sys/types.h>
- #include<netinet/in.h>
- #include<sys/wait.h>
- #include<arpa/inet.h>
- #include<unistd.h>
-
- #define SERVPORT 6123 //设定服务器服务端口
- #define MAX_LISTEN_SOCK_NUM 20 //设定可监听套接字的最大个数为20
- int main()
- {
-
- int sockfd,client_fd;
- struct sockaddr_in my_addr;
- struct sockaddr_in client_addr;
- int i;
-
- if((sockfd=socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))==-1){
- perror("套接字创建失败!/n");
- exit(1);
- }
-
-
- int err,sock_reuse=1;
-
-
-
-
-
-
-
- int opt = 1;
- socklen_t len=sizeof(int);
-
-
- my_addr.sin_family=AF_INET;
- my_addr.sin_port=htons(SERVPORT);
- my_addr.sin_addr.s_addr=INADDR_ANY;
- bzero(&(my_addr.sin_zero),8);
-
- if(bind(sockfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr))==-1){
- perror("绑定失败!/n");
- exit(1);
- }
-
- if((listen(sockfd,MAX_LISTEN_SOCK_NUM))==-1){
- perror("设置监听失败!/n");
- exit(1);
- }
- printf("套接字进入监听状态,等待请求连接:/n");
-
-
- while(1){
-
-
- socklen_t sin_size=sizeof(struct sockaddr_in);
- if((client_fd=accept(sockfd,(struct sockaddr *)&client_addr,&sin_size))==-1){
- perror("接受连接失败!/n");
- continue;
- }
-
-
-
- if((getsockopt(client_fd,SOL_SOCKET,SO_KEEPALIVE,(char*)&opt,&len))==0){
- printf("SO_KEEPALIVE Value: %d/n", opt);
- }
- printf("接到一个来自%s的连接/n",inet_ntoa(client_addr.sin_addr));
-
-
- for(i=0; i<3; i++){
-
- if(send(client_fd,"您好,您已经连接成功!/n",50,0)==-1){
- perror("发送通知信息失败!/n");
- exit(0);
- }
- else
- {
- printf("成功: %d/n", i);
- }
- sleep(10);
- }
-
- while(1)
- {
- if(send(client_fd,"abcdef",6,0)==-1){
- perror("发送通知信息失败!/n");
- exit(0);
- }
- else
- {
- printf("成功: %d/n", i);
- }
- i++;
- }
-
- close(client_fd);
- }
-
- return 0;
- }
客户端代码,和一般的客户端不一样
- #include<stdio.h>
- #include<stdlib.h>
- #include<error.h>
- #include<string.h>
- #include<netdb.h>
- #include<sys/types.h>
- #include<netinet/in.h>
- #include<sys/socket.h>
- #include<unistd.h>
- #include<arpa/inet.h>
- #include <netinet/tcp.h>
-
- #include <errno.h>
-
-
- #define MAXDATASIZE 100
- int main()
- {
- int sockfd,nbytes,serv_port;
- char buf_serv_ip[16],buf[260];
- struct sockaddr_in serv_addr;
-
-
-
- if((sockfd=socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))==-1){
- perror("创建套接字失败!/n");
- exit(1);
- }
-
-
-
- int KeepAlive=1;
- socklen_t KPlen=sizeof(int);
-
-
-
-
- if(setsockopt(sockfd,SOL_SOCKET,SO_KEEPALIVE,(char *)&KeepAlive,KPlen)!=0){
- perror("设置周期测试连接是否仍存活失败!/n");
- exit(1);
- }
-
- int keepIdle = 10;
- int keepInterval = 1;
- int keepCount = 3;
- setsockopt(sockfd,SOL_TCP,TCP_KEEPINTVL,(void *)&keepIdle,sizeof(keepIdle));
- setsockopt(sockfd,SOL_TCP,TCP_KEEPIDLE,(void *)&keepInterval,sizeof(keepInterval));
- setsockopt(sockfd,SOL_TCP,TCP_KEEPCNT,(void *)&keepCount,sizeof(keepCount));
-
-
-
- printf("请输入要连接主机的IP地址:/n");
- scanf("%s",buf_serv_ip);
- printf("请输入要连接主机的端口号:/n");
- scanf("%d",&serv_port);
-
-
- serv_addr.sin_family=AF_INET;
- serv_addr.sin_addr.s_addr=inet_addr(buf_serv_ip);
- serv_addr.sin_port=htons(serv_port);
- bzero(&(serv_addr.sin_zero),8);
- if(connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(struct sockaddr))==-1){
- perror("连接服务器失败!/n");
- exit(1);
- }
-
-
-
- if((getsockopt(sockfd,SOL_SOCKET,SO_KEEPALIVE,(char*)&KeepAlive,&KPlen))==0){
- printf("SO_KEEPALIVE Value: %d/n", KeepAlive);
- }
-
-
-
- printf("连接服务器成功!/n");
-
-
-
- int i =0;
- int res = 0;
- int errcode;
- fd_set readmask;
- struct timeval timeout;
-
- while(1){
-
- FD_ZERO(&readmask);
- FD_SET(sockfd, &readmask);
- timeout.tv_sec = 1;
- timeout.tv_usec = 0;
-
-
- if ((res = select(sockfd + 1, &readmask, NULL, NULL, &timeout)) < 0)
- {
- printf("the socket is error/n");
- exit(1);
- }
-
- printf("select return %d/n", res);
-
- if(res == 0)
- {
- int sockfdtemp;
- errno = 0;
- printf("连接超时/n");
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- continue;
-
- }
-
-
-
- if( (sockfd != -1 ) && FD_ISSET(sockfd, &readmask) )
- {
- printf("the socket is ok/n");
- memset(buf, 0, 260);
- errno = 0;
- if((nbytes=recv(sockfd,buf,260,0))==-1){
- printf("接受数据失败!/n");
- errcode = errno;
- if(errcode == ETIMEDOUT)
- {
- printf("******服务器挂掉 %d : %d /n", errno, ETIMEDOUT);
- exit(1);
- }
- }
- if (nbytes == 0)
- {
- printf("数据为空: %d/n", i);
- }
- else
- {
- buf[nbytes]='/0';
- printf("接受的数据为:%d/n", i);
- }
-
- }else
- {
- printf("the socket is not OK/n");
- exit(1);
-
- }
-
-
- i++;
- }
-
- close(sockfd);
- return 0;
- }
http://blog.csdn.net/spche/article/details/5984968