心跳包机制及Socket通信服务的心跳包

本文转自http://www.cppblog.com/tx7do/archive/2009/11/09/100513.html http://xue08161981.blog.163.com/blog/static/324996772009101010852137/

 心跳包之所以叫心跳包是因为:它像心跳一样每隔固定时间发一次,以此来告诉服务器,这个客户端还活着。事实上这是为了保持长连接,至于这个包的内容,是没有什么特别规定的,不过一般都是很小的包,或者只包含包头的一个空包。
    在TCP的机制里面,本身是存在有心跳包的机制的,也就是TCP的选项:SO_KEEPALIVE。系统默认是设置的2小时的心跳频率。但是它检查不到机器断电、网线拔出、防火墙这些断线。而且逻辑层处理断线可能也不是那么好处理。一般,如果只是用于保活还是可以的。
    心跳包一般来说都是在逻辑层发送空的echo包来实现的。下一个定时器,在一定时间间隔下发送一个空包给客户端,然后客户端反馈一个同样的空包回来,服务器如果在一定时间内收不到客户端发送过来的反馈包,那就只有认定说掉线了。
    其实,要判定掉线,只需要send或者recv一下,如果结果为零,则为掉线。但是,在长连接下,有可能很长一段时间都没有数据往来。理论上说,这个连接是一直保持连接的,但是实际情况中,如果中间节点出现什么故障是难以知道的。更要命的是,有的节点(防火墙)会自动把一定时间之内没有数据交互的连接给断掉。在这个时候,就需要我们的心跳包了,用于维持长连接,保活。
    在获知了断线之后,服务器逻辑可能需要做一些事情,比如断线后的数据清理呀,重新连接呀……当然,这个自然是要由逻辑层根据需求去做了。
    总的来说,心跳包主要也就是用于长连接的保活和断线处理。一般的应用下,判定时间在30-40秒比较不错。如果实在要求高,那就在6-9秒。

 

在一些系统中,经常用到客户端和服务器之间的通信,服务器要时刻知道客户端的网络连接状态,这大概就是所谓的“心跳包”。

下面是客户端心跳包核心代码:

# region ++++++++++++++++++++ 客户端的感觉系统

        //启动记时器

        public void BeginTheTimer()

        {

            //th_UserLogin();

            //这里只是要一个object类型数据,用它做为下面Timer的参数之一,没有其它意思

            object myobject = (object)7;

            //暂时设定为1秒钟启动一次!

            System.Threading.Timer t = new System.Threading.Timer

            (new System.Threading.TimerCallback(testTheNet), myobject, 1000, 1000);

        }

        //启动监视"已登录用户通信情况"的线程

        public void testTheNet(object myobject)  

        {

            //UserPassport up=new UserPassport();

            Thread sendMyPulseThPro = new Thread(new ThreadStart(delegateSendMyPulse));

            sendMyPulseThPro.Start();

        }  

        

        /// <summary>

        /// 每隔1秒就是要来做这些事情的

        /// </summary>

        public void delegateSendMyPulse()

        {

            loginServer lser = new loginServer();

            Login l = new Login();

            l.Id = lser.MyLogin.Id;

            l.ClientTypeVersion = version;

            l.RequestType = 3;          

            //3是确认联接正常的一个信号(让服务知道它与服务器的联接是正常的)

            loginServer lserver = new loginServer();  

            //启动一个新线程去发送数据          

            Thread thSendDat2 = new Thread

            (new ParameterizedThreadStart(lserver.delgSendDataMethod));

            thSendDat2.Start(l);

            thSendDat2.IsBackground = true;

            //标记我已经发送出去一次数据了

            longinserver.MyLostTime += 1;

            //如果外发了3次请求暗号后仍不见服务器的回应,则认为客户端已经与服务器断开联系了

            if(longinserver.MyLostTime>=3)

            {

                //停止Timer

                //告诉用户:“你已经与服务器失去联系了…………”

                longinserver.Controls["txtShowMsg"].Text = "You have lost the connect!";

            }

        }

# endregion +++++++++++++++++++++ 客户端的感觉系统

下面是服务器端核心代码如下:

# region +++++++++++++++++++++++ 服务器的感觉系统

        //启动记时器

        public void LoadTheTimer()

        { 

            object o=(object)loginedCount++;

            UserPassport up = new UserPassport();

            //暂时设定为1秒钟启动一次!

            System.Threading.Timer t = new System.Threading.Timer

            (new System.Threading.TimerCallback(watchTheLoginUser), o, 1000, 1000);            

                   }

        //启动监视"已登录用户通信情况"的线程

        public void watchTheLoginUser(object o)

        {

            //UserPassport up=new UserPassport();

            Thread checktheloginuser = new Thread(new ThreadStart(iAmAWatcher));

            checktheloginuser.Start();

        }

        //真正做事的工人:这个工人的使命是每隔1秒钟后就查看一下登记薄

        //registry里面有谁没有定时来向服务器报到了,如果出现谁三次检查都没有签到则除之名

        public void iAmAWatcher()

        {

            this.txtLogin.Text += "@+";

            int index = 0;

            for (index = 0; index < loginedCount; index++)

            {

                if (myRegistry[index].alive==false&&registry[index].studentID!="")

                {

                    lock(this)

                    {

                        //坏(未到)记录增加一次

                        myRegistry[index].no_check_in_count += 1;           

                   

                        if (myRegistry[index].no_check_in_count >= 3)

                        {

                            //this.lblShowMsg.Text = "the student" 

                            //this.lblShowMsg.Text += registry[index].studentID.ToString() 

                            //this.lblShowMsg.Text += "is diaoxianle!";

                            this.txtLogin.Text += "88";

                            //标记该人已经与服务器失去连接了,因为他有连续3次的未到记录存在

                            registry[index].studentID = "";

                            registry[index].StudentName = "";

                            registry[index].StudentIP = "";

                            registry[index].status = 2;      //掉线

                            

                        }

                    }

                }

            }

        }  //定时检查在线人目前状态

# endregion +++++++++++++++++++ 服务器的感觉系统

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: TCP通信心跳包是在TCP连接中发送的一种探测包,用于检测连接是否仍然存活。下面是一个用C语言实现的TCP通信心跳包的简单示例源码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <errno.h> #define PORT 8080 #define MAX_BUFFER_SIZE 1024 #define HEARTBEAT_INTERVAL 10 // 心跳包发送间隔,单位为秒 int main() { int sockfd; struct sockaddr_in serverAddr; char buffer[MAX_BUFFER_SIZE]; int len; int heartbeatCount = 0; // 创建socket sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("Fail to create socket"); exit(errno); } // 初始化服务器地址 memset(&serverAddr, 0, sizeof(serverAddr)); serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(PORT); serverAddr.sin_addr.s_addr = inet_addr("服务器IP地址"); // 连接服务器 if (connect(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) { perror("Fail to connect server"); exit(errno); } // 开始心跳包通信 while (1) { // 发送心跳包 sprintf(buffer, "Heartbeat: %d", heartbeatCount); len = send(sockfd, buffer, strlen(buffer), 0); if (len < 0) { perror("Fail to send heartbeat"); exit(errno); } // 接收服务器返回数据 len = recv(sockfd, buffer, sizeof(buffer), 0); if (len < 0) { perror("Fail to receive data"); exit(errno); } else if (len > 0) { buffer[len] = '\0'; printf("Receive from server: %s\n", buffer); } // 延时一段时间再发送下一个心跳包 sleep(HEARTBEAT_INTERVAL); heartbeatCount++; } // 关闭连接 close(sockfd); return 0; } ``` 以上示例代码实现了一个客户端程序,使用了socket库函数进行TCP连接的创建和通信。程序中通过send函数发送心跳包数据,然后通过recv函数接收服务器返回的数据,然后延时一段时间后再次发送心跳包。这样循环进行,实现了TCP通信心跳包功能。请注意替换代码中的"服务器IP地址"为实际的服务器IP地址。 ### 回答2: 以下是一个基于C语言实现的TCP通信心跳包的源码示例: #include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <string.h> #define SERVER_IP "127.0.0.1" #define SERVER_PORT 8080 #define BUFFER_SIZE 1024 #define HEARTBEAT_INTERVAL 5 void send_heartbeat(int sockfd) { char heartbeat_msg[] = "heartbeat"; send(sockfd, heartbeat_msg, strlen(heartbeat_msg), 0); } int main() { int sockfd; struct sockaddr_in server_addr; // 创建套接字 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("Failed to create socket"); exit(1); } // 设置服务器地址结构 memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(SERVER_PORT); if (inet_pton(AF_INET, SERVER_IP, &(server_addr.sin_addr)) <= 0) { perror("Invalid server IP address"); exit(1); } // 连接服务器 if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) { perror("Failed to connect to server"); exit(1); } // 设置心跳定时器 int heartbeat_timer = 0; while (1) { // 发送心跳包 if (heartbeat_timer >= HEARTBEAT_INTERVAL) { send_heartbeat(sockfd); heartbeat_timer = 0; } // 接收服务器响应 char buffer[BUFFER_SIZE]; int recv_size = recv(sockfd, buffer, BUFFER_SIZE, MSG_DONTWAIT); if (recv_size > 0) { // 处理服务器响应 buffer[recv_size] = '\0'; printf("Received message: %s\n", buffer); } // 模拟其他业务操作 printf("Do something else...\n"); // 更新心跳定时器 sleep(1); heartbeat_timer++; } // 关闭套接字 close(sockfd); return 0; } 这段代码中,首先创建了一个套接字(socket),然后设置服务器地址结构,使用 connect 函数连接到服务器。之后,通过一个循环来完成心跳包的发送和接收服务器响应的操作。其中,发送心跳包的函数 send_heartbeat 会在一定时间间隔内被调用,并使用 send 函数将心跳包数据发送到服务器。接收服务器响应则使用 recv 函数,并使用 sleep 函数来控制心跳时间间隔。整个循环会不断重复,直到程序被终止。最后,关闭套接字并返回。 ### 回答3: 以下是一个使用C语言实现的TCP通信心跳包的简单源码示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define SERVER_IP "127.0.0.1" #define SERVER_PORT 9999 #define HEARTBEAT_INTERVAL 5 void heartbeat(int sockfd) { char *msg = "Heartbeat"; while (1) { if (send(sockfd, msg, strlen(msg), 0) < 0) { perror("Error sending heartbeat"); break; } sleep(HEARTBEAT_INTERVAL); } } int main() { int sockfd; struct sockaddr_in server_addr; // 创建socket if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("Error creating socket"); exit(EXIT_FAILURE); } // 设置server_addr结构 memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(SERVER_PORT); if (inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr) <= 0) { perror("Error setting server address"); exit(EXIT_FAILURE); } // 连接到服务器 if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) { perror("Error connecting to server"); exit(EXIT_FAILURE); } // 启动心跳包发送 heartbeat(sockfd); // 关闭socket连接 close(sockfd); return 0; } ``` 以上代码实现了一个TCP客户端,每5秒向服务器发送一次心跳包。这个心跳包中包含一个固定的字符串"Heartbeat"。首先,代码创建一个socket并设置服务器的IP地址和端口号。然后,通过connect函数与服务器建立连接。之后,在一个无限循环中,使用send函数发送心跳包字符串,然后通过sleep函数等待5秒。如果发送失败,则会输出错误信息并退出循环。最后,当循环退出后,关闭socket连接。 请注意,这只是一个简单的心跳包示例,实际应用中可能需要根据具体需求对其进行调整和改进。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值