SO_REUSEPORT 之 TCP负载均衡验证

news/2024/9/20 1:20:25/ 标签: tcp/ip, 负载均衡, 服务器

首先启动两个tcp server, 代码里开启 SO_REUSEPORT
 

[my_test@localhost test]$ ./tcp_server_reuseport &
[1] 1864
[my_test@localhost test]$ Server listening on port 8888[my_test@localhost test]$ ./tcp_server_reuseport &
[2] 1865
[my_test@localhost test]$ Server listening on port 8888[my_test@localhost test]$ ps -ef|grep tcp_server_reuseport
my_test         1864    1443  0 23:11 pts/0    00:00:00 ./tcp_server_reuseport
my_test         1865    1443  0 23:11 pts/0    00:00:00 ./tcp_server_reuseport

启动10条客户端连接:

[my_test@localhost test]$ ./tcp_client_reuseport
Message sent
Server response: Welcome to the server! Server PID: 1865Message sent
Server response: Welcome to the server! Server PID: 1864Message sent
Server response: Welcome to the server! Server PID: 1865Message sent
Server response: Welcome to the server! Server PID: 1864Message sent
Server response: Welcome to the server! Server PID: 1864Message sent
Server response: Welcome to the server! Server PID: 1865Message sent
Server response: Welcome to the server! Server PID: 1865Message sent
Server response: Welcome to the server! Server PID: 1865Message sent
Server response: Welcome to the server! Server PID: 1864Message sent
Server response: Welcome to the server! Server PID: 1864

从回复的server 进程id 可见,负载均衡做的很好。

追踪内核调用链(内核版本5.10.216  x86_64):

在server端收到client的SYN连接请求时会触发 __inet_lookup_listener -> inet_lhash2_lookup -> lookup_reuseport -> reuseport_select_sock 通过哈希选择一个Listen Socket来处理这个连接请求。

(gdb) b reuseport_select_sock
Breakpoint 1 at 0xffffffff8199ac80: file net/core/sock_reuseport.c, line 277.
(gdb) c
Continuing.
[New Thread 2061]
[Switching to Thread 2061]Thread 293 hit Breakpoint 1, reuseport_select_sock (sk=sk@entry=0xffff888038c90000, hash=317205834, skb=skb@entry=0xffff88800a90dce0,hdr_len=hdr_len@entry=40) at net/core/sock_reuseport.c:277
277     net/core/sock_reuseport.c: No such file or directory.
(gdb) bt
#0  reuseport_select_sock (sk=sk@entry=0xffff888038c90000, hash=317205834, skb=skb@entry=0xffff88800a90dce0, hdr_len=hdr_len@entry=40)at net/core/sock_reuseport.c:277
#1  0xffffffff81a03ff8 in lookup_reuseport (hnum=8888, daddr=0, sport=21715, saddr=251789322, doff=40, skb=0xffff88800a90dce0,sk=0xffff888038c90000, net=0xffffffff82a1ac40 <init_net>) at net/ipv4/inet_hashtables.c:265
#2  lookup_reuseport (hnum=8888, daddr=0, sport=21715, saddr=251789322, doff=40, skb=0xffff88800a90dce0, sk=0xffff888038c90000,net=0xffffffff82a1ac40 <init_net>) at net/ipv4/inet_hashtables.c:255
#3  inet_lhash2_lookup (net=net@entry=0xffffffff82a1ac40 <init_net>, ilb2=<optimized out>, skb=skb@entry=0xffff88800a90dce0,doff=doff@entry=40, saddr=saddr@entry=251789322, sport=sport@entry=21715, daddr=0, hnum=8888, dif=2, sdif=0)at net/ipv4/inet_hashtables.c:293
#4  0xffffffff81a042f3 in __inet_lookup_listener (net=net@entry=0xffffffff82a1ac40 <init_net>,hashinfo=hashinfo@entry=0xffffffff832a69c0 <tcp_hashinfo>, skb=skb@entry=0xffff88800a90dce0, doff=doff@entry=40,saddr=saddr@entry=251789322, sport=sport@entry=21715, daddr=<optimized out>, hnum=8888, dif=2, sdif=0)at net/ipv4/inet_hashtables.c:361
#5  0xffffffff81a25978 in __inet_lookup (hashinfo=0xffffffff832a69c0 <tcp_hashinfo>, sdif=0, refcounted=<synthetic pointer>, dif=2,dport=<optimized out>, daddr=251789322, sport=<optimized out>, saddr=251789322, doff=<optimized out>, skb=0xffff88800a90dce0,net=0xffffffff82a1ac40 <init_net>) at ./include/net/inet_hashtables.h:343
#6  __inet_lookup_skb (hashinfo=0xffffffff832a69c0 <tcp_hashinfo>, sdif=0, refcounted=<synthetic pointer>, dport=<optimized out>,sport=<optimized out>, doff=<optimized out>, skb=0xffff88800a90dce0) at ./include/net/inet_hashtables.h:379
#7  tcp_v4_rcv (skb=0xffff88800a90dce0) at net/ipv4/tcp_ipv4.c:1984
#8  0xffffffff819f922b in ip_protocol_deliver_rcu (net=0xffffffff82a1ac40 <init_net>, skb=0xffff88800a90dce0,protocol=<optimized out>) at net/ipv4/ip_input.c:204
#9  0xffffffff819f93ef in ip_local_deliver_finish (net=<optimized out>, sk=<optimized out>, skb=<optimized out>)at ./include/linux/skbuff.h:2533
#10 0xffffffff819f94fa in NF_HOOK (sk=0x0 <fixed_percpu_data>, pf=2 '\002', hook=1, in=<optimized out>, out=0x0 <fixed_percpu_data>,okfn=0xffffffff819f93b0 <ip_local_deliver_finish>, skb=0xffff88800a90dce0, net=0xffffffff82a1ac40 <init_net>)at ./include/linux/netfilter.h:296
#11 NF_HOOK (pf=2 '\002', sk=0x0 <fixed_percpu_data>, out=0x0 <fixed_percpu_data>, okfn=0xffffffff819f93b0 <ip_local_deliver_finish>,in=<optimized out>, skb=0xffff88800a90dce0, net=0xffffffff82a1ac40 <init_net>, hook=1) at ./include/linux/netfilter.h:290
#12 ip_local_deliver (skb=0xffff88800a90dce0) at net/ipv4/ip_input.c:252
#13 0xffffffff819f95e3 in NF_HOOK (sk=0x0 <fixed_percpu_data>, pf=2 '\002', hook=0, in=0xffff88800391b000,out=0x0 <fixed_percpu_data>, okfn=0xffffffff819f8c40 <ip_rcv_finish>, skb=0xffff88800a90dce0, net=0xffffffff82a1ac40 <init_net>)at ./include/linux/netfilter.h:296
#14 NF_HOOK (pf=2 '\002', sk=0x0 <fixed_percpu_data>, out=0x0 <fixed_percpu_data>, okfn=0xffffffff819f8c40 <ip_rcv_finish>,
--Type <RET> for more, q to quit, c to continue without paging--in=0xffff88800391b000, skb=0xffff88800a90dce0, net=0xffffffff82a1ac40 <init_net>, hook=0) at ./include/linux/netfilter.h:290
#15 ip_rcv (skb=0xffff88800a90dce0, dev=0xffff88800391b000, pt=<optimized out>, orig_dev=<optimized out>) at net/ipv4/ip_input.c:551
#16 0xffffffff819714a4 in __netif_receive_skb_one_core (skb=<optimized out>, pfmemalloc=<optimized out>) at net/core/dev.c:5375
#17 0xffffffff819716e9 in process_backlog (napi=0xffff88807dc2e3d0, quota=64) at net/core/dev.c:6396
#18 0xffffffff81972fce in napi_poll (repoll=0xffffc90000003f60, n=0xffff88807dc2e3d0) at net/core/dev.c:6847
#19 net_rx_action (h=<optimized out>) at net/core/dev.c:6917
#20 0xffffffff820000b7 in __do_softirq () at kernel/softirq.c:298
#21 0xffffffff81e0106f in asm_call_on_stack () at arch/x86/entry/entry_64.S:801
#22 0xffffffff81022372 in __run_on_irqstack (func=<optimized out>) at ./arch/x86/include/asm/irq_stack.h:26
#23 run_on_irqstack_cond (regs=0x0 <fixed_percpu_data>, func=<optimized out>) at ./arch/x86/include/asm/irq_stack.h:77
#24 do_softirq_own_stack () at arch/x86/kernel/irq_64.c:77
#25 0xffffffff8106c7aa in do_softirq () at kernel/softirq.c:343
#26 0xffffffff8106c7fa in do_softirq () at ./arch/x86/include/asm/preempt.h:26
#27 __local_bh_enable_ip (ip=ip@entry=18446744071589316362, cnt=cnt@entry=512) at kernel/softirq.c:195
#28 0xffffffff819fc71b in local_bh_enable () at ./include/linux/bottom_half.h:32
#29 rcu_read_unlock_bh () at ./include/linux/rcupdate.h:806
#30 ip_finish_output2 (net=<optimized out>, sk=<optimized out>, skb=<optimized out>) at net/ipv4/ip_output.c:238
#31 0xffffffff819feee8 in ip_finish_output (skb=0xffff88800a90dce0, sk=0xffff888038c92bc0, net=0xffffffff82a1ac40 <init_net>)at net/ipv4/ip_output.c:325
#32 NF_HOOK_COND (pf=2 '\002', hook=4, okfn=0xffffffff819fd670 <ip_finish_output>, cond=<optimized out>, out=<optimized out>,in=<optimized out>, skb=0xffff88800a90dce0, sk=0xffff888038c92bc0, net=0xffffffff82a1ac40 <init_net>)at ./include/linux/netfilter.h:285
#33 ip_output (net=0xffffffff82a1ac40 <init_net>, sk=0xffff888038c92bc0, skb=0xffff88800a90dce0) at net/ipv4/ip_output.c:439
#34 0xffffffff819fe982 in __ip_queue_xmit (sk=0xffff888038c92bc0, skb=0xffff88800a90dce0, fl=0xffff888038c92f20, tos=<optimized out>)at net/ipv4/ip_output.c:540
#35 0xffffffff819febbc in ip_queue_xmit (sk=<optimized out>, skb=<optimized out>, fl=<optimized out>) at ./include/net/inet_sock.h:302
#36 0xffffffff81a1bef6 in __tcp_transmit_skb (sk=sk@entry=0xffff888038c92bc0, skb=0xffff88800a90dce0, skb@entry=0xffff88800a90dc00,clone_it=clone_it@entry=1, gfp_mask=<optimized out>, rcv_nxt=<optimized out>) at net/ipv4/tcp_output.c:1407
#37 0xffffffff81a1c8ed in tcp_transmit_skb (gfp_mask=<optimized out>, clone_it=1, skb=0xffff88800a90dc00, sk=0xffff888038c92bc0)at ./include/linux/tcp.h:439
#38 tcp_connect (sk=sk@entry=0xffff888038c92bc0) at net/ipv4/tcp_output.c:3888
#39 0xffffffff81a22c90 in tcp_v4_connect (sk=0xffff888038c92bc0, uaddr=0xffffc90000d43e88, addr_len=<optimized out>)at net/ipv4/tcp_ipv4.c:314
--Type <RET> for more, q to quit, c to continue without paging--
#40 0xffffffff81a3d87c in __inet_stream_connect (sock=sock@entry=0xffff88803652f000, uaddr=0x12e82d4a,uaddr@entry=0xffffc90000d43e88, addr_len=177265888, addr_len@entry=16, flags=40, flags@entry=2, is_sendmsg=21715,is_sendmsg@entry=0) at net/ipv4/af_inet.c:666
#41 0xffffffff81a3db41 in inet_stream_connect (sock=0xffff88803652f000, uaddr=0xffffc90000d43e88, addr_len=16, flags=2)at net/ipv4/af_inet.c:730
#42 0xffffffff8194bdc5 in __sys_connect (fd=<optimized out>, uservaddr=0x7ffe8421f910, addrlen=16) at net/socket.c:1882
#43 0xffffffff8194be01 in __do_sys_connect (addrlen=<optimized out>, uservaddr=<optimized out>, fd=<optimized out>)at net/socket.c:1892
#44 __se_sys_connect (addrlen=<optimized out>, uservaddr=<optimized out>, fd=<optimized out>) at net/socket.c:1889
#45 __x64_sys_connect (regs=<optimized out>) at net/socket.c:1889
#46 0xffffffff81c38090 in do_syscall_64 (nr=<optimized out>, regs=0xffffc90000d43f58) at arch/x86/entry/common.c:46
#47 0xffffffff81e0011f in entry_SYSCALL_64 () at arch/x86/entry/entry_64.S:125
#48 0x0000000000000000 in ?? ()

具体代码如下:

 server端演示代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>#define PORT 8888
#define MAX_PENDING_CONNECTIONS 10int main() {int server_fd, new_socket;struct sockaddr_in address;int opt = 1;int addrlen = sizeof(address);// 创建套接字if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {perror("socket failed");exit(EXIT_FAILURE);}// 设置套接字选项if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt))) {perror("setsockopt");exit(EXIT_FAILURE);}address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port = htons(PORT);// 将套接字绑定到指定的地址和端口if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) {perror("bind failed");exit(EXIT_FAILURE);}// 开始监听连接if (listen(server_fd, MAX_PENDING_CONNECTIONS) < 0) {perror("listen");exit(EXIT_FAILURE);}printf("Server listening on port %d\n", PORT);while(1) {// 接受新连接if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) {perror("accept");exit(EXIT_FAILURE);}printf("New connection from %s:%d\n", inet_ntoa(address.sin_addr), ntohs(address.sin_port));// 向客户端发送消息,包含当前进程IDchar welcome_message[100];int pid = getpid(); // 获取当前进程的 IDsprintf(welcome_message, "Welcome to the server! Server PID: %d\n", pid);send(new_socket, welcome_message, strlen(welcome_message), 0);// 关闭与客户端的连接close(new_socket);}return 0;
}

客户端演示代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define PORT 8888
#define SERVER_IP "10.0.2.15" // 服务器 IP 地址
#define MESSAGE "Hello from client"int main() {int sock = 0;struct sockaddr_in serv_addr;char message[1024] = {0};char buffer[1024] = {0};int i = 0;while (i++ < 10) {// 创建套接字if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {perror("socket creation error");exit(EXIT_FAILURE);}serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(PORT);if(inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr) <= 0) {perror("invalid address / address not supported");exit(EXIT_FAILURE);}// 连接到服务器if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {perror("connection failed");exit(EXIT_FAILURE);}// 向服务器发送消息send(sock, MESSAGE, strlen(MESSAGE), 0);printf("Message sent\n");// 接收服务器的响应if (recv(sock, buffer, sizeof(buffer), 0) < 0) {perror("recv failed");exit(EXIT_FAILURE);}printf("Server response: %s\n", buffer);// 关闭套接字close(sock);}return 0;
}


http://www.ppmy.cn/news/1462738.html

相关文章

《Google 软件工程》读书笔记

1. 写在前面 在图书馆瞎逛&#xff0c;偶然瞄见一本《Google 软件工程》Titus Winters, Tom Manshreck, Hyrum Wright 著。主要是在这一排的书架上就这本书看着挺新的&#xff08;不知道为什么有一种喜欢看新书的情节&#xff09;&#xff0c;而且最近被领导老批评&#xff0c;…

数据结构-队列(带图详解)

目录 队列的概念 画图理解队列 代码图理解 代码展示(注意这个队列是单链表的结构实现) Queue.h(队列结构) Queue.c(函数/API实现) main.c(测试文件) 队列的概念 队列&#xff08;Queue&#xff09;是一种基础的数据结构&#xff0c;它遵循先进先出&#xff08;First In …

基础—SQL—通用语法及分类

一、SQL的通用基本语法 &#xff08;1&#xff09;SQL语句可以单行或多行书写&#xff08;以分号结尾&#xff09;。 &#xff08;2&#xff09;在编写SQL语句的时候&#xff0c;如果长度比较长&#xff0c;我们可以允许空格/缩进来增强语句的可读性&#xff0c;而且空格或者…

括号生成[中等]

优质博文&#xff1a;IT-BLOG-CN 一、题目 数字n代表生成括号的对数&#xff0c;请你设计一个函数&#xff0c;用于能够生成所有可能的并且 有效的 括号组合。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;["((()))","(()())","(())(…

2024 一键批量下载微博内容/图片/视频/评论/转发数据,导出excel和pdf

以李健的微博为例&#xff0c;抓取2010-2024年所有的微博数据excel&#xff0c;包含微博链接&#xff0c;微博内容&#xff0c;发布时间&#xff0c;点赞数&#xff0c;转发数&#xff0c;评论数&#xff0c;话题等。 每个月的微博转评赞总数曲线&#xff0c;2015年是高峰。 微…

opencv--形态学(开运算、闭运算、形态学梯度、顶帽、黑帽)

开运算 先腐蚀再膨胀&#xff0c;消除细小点、毛刺、连接点等等情况 闭运算 先膨胀再腐蚀&#xff0c;填充孔洞、增强连接点等等情况&#xff0c;或者大家说的增加明亮度 形态学梯度 使用膨胀的图减去腐蚀的图&#xff0c;简单理解就是二值化后形状膨胀后会使得物体变大&am…

APP广告变现怎么实现的,背后逻辑是什么?

广告变现的实现主要基于以下几个关键步骤和逻辑&#xff1a; 用户获取与留存&#xff1a;首先&#xff0c;APP需要吸引足够的用户并确保他们的留存率。只有拥有庞大且活跃的用户基础&#xff0c;APP才能吸引广告商投放广告。因此&#xff0c;开发者需要通过优化APP质量、提升用…

[实例] Unity Shader 逐像素漫反射与半兰伯特光照

漫反射光照是Unity中最基本最简单的光照模型&#xff0c;本篇将会介绍在片元着色器中实现反射效果&#xff0c;并会采用半兰伯特光照技术对其进行改进。 1. 逐顶点光照与逐像素光照 在Unity Shader中&#xff0c;我们可以有两个地方可以用来计算光照&#xff1a;在顶点着色器…

后端雪花算法主键ID传到前端变了

Mybatis Plus 的主键策略&#xff1a; /*** id*/TableId(type IdType.ASSIGN_ID)private Long id; 这个主键策略会用雪花算法生成一个 19位的ID&#xff0c;比如 1791006670084734978 现象 后端生成的 id 是正常的&#xff0c;通过 swagger 文档此时获取到的 id 也和数据库中…

GitHub的原理及应用详解(四)

本系列文章简介&#xff1a; GitHub是一个基于Git版本控制系统的代码托管平台&#xff0c;为开发者提供了一个方便的协作和版本管理的工具。它广泛应用于软件开发项目中&#xff0c;包括但不限于代码托管、协作开发、版本控制、错误追踪、持续集成等方面。 GitHub的原理可以简单…

RabbitMQ(二)七种工作模式

文章目录 概述:工作模式&#xff08;七种&#xff09;1. "Hello World!"2. Work Queues&#xff08;工作队列模式&#xff09;3. Publish/Subscribe&#xff08;发布订阅模式&#xff09;4. Routing5. Topics6. RPC7. Publisher Confirms 详细1. "Hello World!&…

哈醉咯最狠

3、通过命令行安装aptitude sudo apt-get install aptitude4、通过命令行利用aptitude 安装fcitx、qtsudo aptitude install fcitx-bin fcitx-table fcitx-config-gtk fcitx-config-gtk2 fcitx-frontend-allsudo aptitude install qt5-default qtcreator qml-module-qtquick-co…

Linux(centos)常用命令

Linux&#xff08;Centos&#xff09;常用命令使用说明文档 切换到/home目录下 使用cd命令切换目录&#xff0c;例如&#xff1a; cd /home列出/home目录下的所有文件 使用ls命令列出目录下的文件和子目录&#xff0c;例如&#xff1a; ls /home新建目录dir1 使用mkdir命…

Linux数组

目录 一.概念 &#xff08;一&#xff09;什么是数组&#xff1f; &#xff08;二&#xff09;数组的表现方式 &#xff08;三&#xff09;数组的数据类型 二.运用数组查看、修改、删除相关信息 &#xff08;1&#xff09;查看数组的元素列表 &#xff08;2&#xff09;查…

物联网应用开发--STM32与机智云通信(ESP8266 Wi-Fi+手机APP+LED+蜂鸣器+SHT20温湿度传感器)

实现目标 1、熟悉机智云平台&#xff0c;会下载APP 2、熟悉新云平台创建产品&#xff0c;项目虚拟调试 3、掌握云平台生成MCU代码&#xff0c;并移植。机智云透传固件的下载 4、具体目标&#xff1a;&#xff08;1&#xff09;注册机智云平台&#xff1b;&#xff08;2&…

自动驾驶---Tesla的自动驾驶技术进化史(PerceptionPlanning)

1 前言 笔者在专栏《自动驾驶Planning模块》中已经详细讲解了传统自动驾驶Planning模块的内容&#xff1a;包括行车的Behavior Planning和Motion Planning&#xff0c;以及低速记忆泊车的Planning&#xff08;最开始有15篇&#xff0c;目前逐渐更新到17篇&#xff09;。读者对整…

【微信小程序开发】小程序前后端交互--发送网络请求实战解析

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

python写的五个小游戏___浔川python社

一&#xff1a; 猜词游戏 # 猜词游戏 import random words [apple, , orange, pear] word random.choice(words) mixed_word list(word) random.shuffle(mixed_word) mixed_word .join(mixed_word) print(猜词游戏开始!) print(打乱后的词是:, mixed_word) while True:gue…

Android 屏保开关

设置-显示-屏保&#xff0c; 打开关闭 设置代码在 ./packages/apps/Settings/src/com/android/settings/dream/DreamMainSwitchPreferenceController.java &#xff0c; Overridepublic boolean isChecked() {return mBackend.isEnabled();}Overridepublic boolean setChecke…