带外数据以及Linux下的设置

带外数据的概念:建立连接的双端,如果有一端有紧急的消息,可以立刻通知对方,而不是通过消息排队的机制进行告知。

TCP没有真正的带外数据,而是设置了紧急指针来实现这一模式的。带外数据只有一个字节,如果发送多个带外数据,那么只有最后一个字符会被作为带外数据进行传输。

接收方如果收到带外数据,内核会向进程发送SIGURG信号,我们可以根据这个信号来调用有关的处理函数。

在之前的博客中,我们使用管道的方式,向主循环中写入信号,防止信号被屏蔽,同时也可以处理多个信号。但是,在这里的心跳检测一般要求我们立刻处理,所以单独罗列出一个信号处理函数处理该信号,也可以认为偷懒一次吧。。。。。。

代码实例

客户端:与服务器建立连接,等待服务器的心跳检测,每接收到一个信号,就立刻回发相同的数据回复。客户端代码如下:

#include <sys/socket.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <signal.h>
#include <fcntl.h>static int clientfd = -1;void tick_handle (int sig) {if (sig != SIGURG) {perror ("wrong signal\n");return;}char c = '\0';recv (clientfd, &c, 1, MSG_OOB);printf ("get urgency data: %c", c);send (clientfd, "u", 1, MSG_OOB);  // 回发紧急数据
}// sig信号注册sig_handle处理函数
void addsig (int sig, void (*sig_handler) (int) ) {struct sigaction sa;bzero (&sa, sizeof (sa) );sa.sa_handler = sig_handler;sa.sa_flags = SA_RESTART;assert (sigaction (sig, &sa, NULL) != -1);
}int main (int argc, char* argv[]) {if (argc != 3) {printf ("Usage: %s <ip of server> <port of server>\n", argv[0]);exit (0);}int port = atoi (argv[2]);if (port < 1024 || port > 65535) {perror ("port error\n");exit (0);}struct sockaddr_in serv;bzero (&serv, sizeof (serv) );if (inet_pton (AF_INET, argv[1], &serv.sin_addr) == -1) {perror ("inet_pton() error\n");exit (1);}serv.sin_family = AF_INET;serv.sin_port = htons (port);clientfd = socket (AF_INET, SOCK_STREAM, 0);if (clientfd < 0) {perror ("socket() error\n");exit (1);}if (connect (clientfd, (struct sockaddr*) &serv, sizeof (serv) ) < 0) {perror ("connect() error\n");exit (1);}//addsig (SIGURG, tick_handle);signal (SIGURG, tick_handle);fcntl (clientfd, F_SETOWN, getpid() );while (true) {char buf[1024];int ret = recv (clientfd, buf, 10, 0);if (ret > 0) {printf ("get data: %s\n", buf);} else if (ret < 0) {perror ("recv() error\n");exit (1);} else {sleep (1);}}exit (0);
}

服务端,我们假设每1秒给客户端一个心跳检测。在这里我们假设是最简单的情况,一个服务器仅仅对应一个客户端,而且每3秒给客户端发送一个测试数据。设置一个cnt全局变量,用于记录客户端的响应次数,如果超过三次没响应就删除这个连接。下面是服务器的代码:

#include <sys/socket.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <signal.h>static int cnt = 0;  // 计数变量
static int clientfd = -1;// sig信号注册sig_handle处理函数
void addsig (int sig, void (*sig_handler) (int) ) {struct sigaction sa;bzero (&sa, sizeof (sa) );sa.sa_handler = sig_handler;sa.sa_flags = SA_RESTART;assert (sigaction (sig, &sa, NULL) != -1);
}// 心跳检测
void tick (int sig) {if (sig != SIGALRM) {return;}send (clientfd, "u", 1, MSG_OOB);  // 发送带外数据printf ("send tick to client %d\n", clientfd);alarm (1); // 每隔一秒一次++cnt;
}// 获取用户的心跳
void getTick (int sig) {if (sig != SIGURG) {return;}cnt = 0;  // 清0char c = '\0';recv (clientfd, &c, 1, MSG_OOB);printf ("get client %d's response %c\n", clientfd, c);
}// 每个客户分配一个进程
void process () {addsig (SIGALRM, tick);addsig (SIGURG, getTick);puts ("process");while (true) {sleep (1);if (cnt >= f 3) {puts ("client doesn't response 3 times, close connection...\n");exit (0);}}
}int main (int argc, char* argv[]) {if (argc != 2) {printf ("Usage: %s <port of server>\n", argv[0]);exit (0);}int port = atoi (argv[1]);if (port < 1024 || port > 65535) {perror ("port error\n");exit (0);}struct sockaddr_in serv;bzero (&serv, sizeof (serv) );serv.sin_family = AF_INET;serv.sin_port = htons (port);serv.sin_addr.s_addr = htonl (INADDR_ANY);int listenfd = socket (AF_INET, SOCK_STREAM, 0);if (listenfd < 0) {perror ("socket() error\n");exit (1);}if (bind (listenfd, (struct sockaddr*) &serv, sizeof (serv) ) < 0) {perror ("bind() error\n");exit (1);}if (listen (listenfd, 32) < 0) {perror ("listen() error\n");exit (1);}while (true) {clientfd = accept (listenfd, NULL, NULL);//puts("new client");if (clientfd < 0) {perror ("accept() error\n");break;}pid_t pid;if ( (pid = fork() ) == 0) {  // 孩子进程close (listenfd);alarm (1);process();puts ("process over");exit (0);}close (clientfd);//sleep (1);}exit (0);
}

TCP通过带外数据实现心跳检测机制相关推荐

  1. TCP协议--带外数据和超时重传

    <Linux高性能服务器编程>阅读笔记: 1. 带外数据   有些传输层协议具有带外(Out Of Band, OOB)数据的概念,用于迅速告知对方本端发生的重要事件.因此带外数据比普通数 ...

  2. 【Linux网络编程】TCP带外数据

    [Linux网络编程]TCP带外数据 [1]TCP 包的部首 TCP带外数据相关概念 紧急字段URG     : 当URG=1时,告诉系统此报文段中有紧急数据,应尽快传送. 紧急指针         ...

  3. Netty 心跳检测机制

    心跳检测机制 目的:就是用于检测 检测通信对方是否还"在线",如果已经断开,就要释放资源 或者 尝试重连. 大概的实现原理就是:在服务器和客户端之间一定时间内没有数据交互时, 即处 ...

  4. 带外数据:TCP紧急模式分析

    TCP并未提供真正意义上的带外数据,而是紧急模式.TCP并未建立新的连接,或者使用独立的逻辑通道,而只是通过紧急模式的机制,在已有的TCP连接上传输带外数据. 发送端 TCP协议栈会为每个套接字维护一 ...

  5. Linux服务器编程 用SIGURG检测带外数据是否到达

    带外数据 带外数据用于迅速告知对方本端发生的重要的事件.它比普通的数据(带内数据)拥有更高的优先级,不论发送缓冲区中是否有排队等待发送的数据,它总是被立即发送.带外数据的传输可以使用一条独立的传输层连 ...

  6. 2022-4-19 同时读取带外数据和正常数据《Linux高性能服务器》笔记

    服务端 #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #include&l ...

  7. netty的编解码、粘包拆包问题、心跳检测机制原理

    文章目录 1. 编码解码器 2. 编解码序列化机制的性能优化 3. Netty粘包拆包 4. Netty心跳检测机制 5. Netty断线自动重连实现 1. 编码解码器 当你通过netty发送或者接受 ...

  8. Netty空闲心跳检测机制

    概述 Netty提供了一个读写空闲心跳检测机制的Handler,用于检测读空闲.写空闲.读写空闲. 如果服务端在一定时间内没有执行读请求,就会触发读空闲事件,一定时间内没有执行写请求,就会触发写空闲事 ...

  9. Netty学习(七):心跳检测机制

    一.什么是心跳检测机制 所谓心跳, 即在 TCP 长连接中, 客户端和服务器之间定期发送的一种特殊的数据包, 通知对方自己还在线, 以确保 TCP 连接的有效性. 心跳机制主要是客户端和服务端长时间连 ...

最新文章

  1. 在使用import语句时
  2. (读) 周鸿祎重新思考360(有感)
  3. 富文本编辑器---笑脸表情(一)
  4. Nginx负载均衡策略之least_conn
  5. python工厂模式 简书_[Python设计模式] 01 - 简单工厂模式
  6. 如何从手机上做风控,设备指纹如何下手?
  7. 【转】利用Eclipse编辑中文资源文件(application_zh_CN.properties )
  8. [转]Qt 之 QFileSystemWatcher
  9. Atitit 数据库view视图使用推荐规范与最佳实践与方法
  10. 数据库基础(常用SQL语句)
  11. 当不知轴承型号时如何寻找轴承故障频率_专家总结的齿轮箱滚动轴承故障诊断方法,值得收藏!...
  12. win10 1909是微软的第几个版本 win10各版本区别
  13. java file seek_Java RandomAccessFile seek()方法
  14. 【按键精灵】sub子程序、调用子程序
  15. 100层楼,2个鸡蛋,最少要几次才能测试出鸡蛋能承受的最大楼层?
  16. 京东2020年Q2财报数据亮眼:超2000亿净收入背后供应链物流价值释放
  17. windows禁用屏幕旋转_如何在Windows 10中禁用屏幕自动旋转
  18. LR之识别图片验证码
  19. 134_人人后台管理系统-立即执行定时任务失败(坑)
  20. 图解 Vue3.0 编译器核心原理(Vue3.0源码解析)

热门文章

  1. java heap 查看_使用VisualVM查看Java Heap Dump
  2. LeetCode 1114. 按序打印
  3. 洛谷 P1983 [NOIP2013 普及组] 车站分级
  4. Python之编写函数
  5. C 库函数 - pow()
  6. !!统计字符(处理字符串)(getline函数使用)
  7. 《深度学习笔记》——训练加速篇
  8. matplotlib——在 Jupyter Notebook中绘制图像时只显示变量信息不显示图片
  9. Python遍历文件夹获取文件名并写入excel
  10. 【less-3】sqli-labs靶场第三关