服务端配置TCP探活,超出探活时间后的行为?

发布于:2025-03-01 ⋅ 阅读:(14) ⋅ 点赞:(0)

server端启动

(完整源码在最后)

配置探活

	setsockopt(client_fd, IPPROTO_TCP, TCP_KEEPIDLE, &(int){5}, sizeof(int));   // 空闲60秒后探测
	setsockopt(client_fd, IPPROTO_TCP, TCP_KEEPINTVL, &(int){10}, sizeof(int));	 // 探测间隔10秒
	setsockopt(client_fd, IPPROTO_TCP, TCP_KEEPCNT, &(int){5}, sizeof(int));	 // 最多探测5次

启动服务端

$ ./net 
Waiting for client connection...

client端telnet建连

telnet 9.134.128.138 8484

连接建立,server开始发送探活包

按配置,TCP_KEEPINTVL=10秒发送一次ack,server主动发起,client收到后回复ack。


15:45:03.184535 IP host-server.8484 > client-server.51878: Flags [.], ack 5, win 510, length 0
15:45:03.184799 IP client-server.51878 > host-server.8484: Flags [.], ack 1, win 502, length 0

15:45:13.424537 IP host-server.8484 > client-server.51878: Flags [.], ack 5, win 510, length 0
15:45:13.424808 IP client-server.51878 > host-server.8484: Flags [.], ack 1, win 502, length 0

15:45:23.664530 IP host-server.8484 > client-server.51878: Flags [.], ack 5, win 510, length 0
15:45:23.664769 IP client-server.51878 > host-server.8484: Flags [.], ack 1, win 502, length 0

15:45:33.904536 IP host-server.8484 > client-server.51878: Flags [.], ack 5, win 510, length 0
15:45:33.904779 IP client-server.51878 > host-server.8484: Flags [.], ack 1, win 502, length 0

15:45:44.144532 IP host-server.8484 > client-server.51878: Flags [.], ack 5, win 510, length 0
15:45:44.144774 IP client-server.51878 > host-server.8484: Flags [.], ack 1, win 502, length 0

15:45:54.384517 IP host-server.8484 > client-server.51878: Flags [.], ack 5, win 510, length 0
15:45:54.384755 IP client-server.51878 > host-server.8484: Flags [.], ack 1, win 502, length 0

15:46:04.624540 IP host-server.8484 > client-server.51878: Flags [.], ack 5, win 510, length 0
15:46:04.624798 IP client-server.51878 > host-server.8484: Flags [.], ack 1, win 502, length 0

客户端配置主动丢掉来自server的包

service iptables start
service iptables status

iptables -L -n --line-number

sudo iptables -A OUTPUT -p tcp --sport 8484 -j DROP

五次失败的探活后,server端报错

server端本来在read上等数据,探活又内核完成,探活失败后,read返回负数错误码。

perror(“read error”);打印结果:read error: Connection timed out

		ssize_t bytes_read = read(client_fd, buffer, BUFFER_SIZE - 1);

		if (bytes_read > 0)
		{
			buffer[bytes_read] = '\0';
			printf("Received: %s\n", buffer);
		}
		else if (bytes_read == 0)
		{
			printf("Connection closed by client[5](@ref)\n");
			break;
		}
		else
		{
			perror("read error");   // <<<<< 走这里
			break;
		}

server端完整代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/tcp.h>

#define BUFFER_SIZE 256

int main()
{
	int server_fd, client_fd;
	struct sockaddr_in server_addr, client_addr;
	socklen_t client_len = sizeof(client_addr);
	char buffer[BUFFER_SIZE];

	if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
	{
		perror("socket creation failed");
		exit(EXIT_FAILURE);
	}

	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = INADDR_ANY;
	server_addr.sin_port = htons(8484);

	if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
	{
		perror("bind failed");
		close(server_fd);
		exit(EXIT_FAILURE);
	}

	if (listen(server_fd, 5) < 0)
	{
		perror("listen failed");
		close(server_fd);
		exit(EXIT_FAILURE);
	}

	printf("Waiting for client connection...\n");

	if ((client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len)) < 0)
	{
		perror("accept failed");
		close(server_fd);
		exit(EXIT_FAILURE);
	}

	int keepalive = 1;
	if (setsockopt(client_fd, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive)) < 0)
	{
		perror("setsockopt(SO_KEEPALIVE) failed");
		close(client_fd);
		close(server_fd);
		exit(EXIT_FAILURE);
	}
	setsockopt(client_fd, IPPROTO_TCP, TCP_KEEPIDLE, &(int){5}, sizeof(int));   // 空闲60秒后探测
	setsockopt(client_fd, IPPROTO_TCP, TCP_KEEPINTVL, &(int){10}, sizeof(int));	 // 探测间隔10秒
	setsockopt(client_fd, IPPROTO_TCP, TCP_KEEPCNT, &(int){5}, sizeof(int));	 // 最多探测5次

	printf("Client connected from %s:%d\n",
		   inet_ntoa(client_addr.sin_addr),
		   ntohs(client_addr.sin_port));

	while (1)
	{
		ssize_t bytes_read = read(client_fd, buffer, BUFFER_SIZE - 1);

		if (bytes_read > 0)
		{
			buffer[bytes_read] = '\0';
			printf("Received: %s\n", buffer);
		}
		else if (bytes_read == 0)
		{
			printf("Connection closed by client[5](@ref)\n");
			break;
		}
		else
		{
			perror("read error");
			break;
		}
	}

	close(client_fd);
	close(server_fd);
	return 0;
}