Linux tcp timewait相处之道

2024-09-06 08:38
文章标签 linux tcp 之道 timewait 相处

本文主要是介绍Linux tcp timewait相处之道,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

关于Time wait 的特殊细节

熟悉tcp网络编程的同学对于timewait 状态可以说是既熟悉又陌生。在繁忙的server端,该状态经常会使得server无法bind,或者耗尽可用的port资源。此时此刻,心里往往不知所以,万般无奈。本文结合实验,spec和代码原理,解释了timewait 的几种处理方案。

参考文献
1) unix networking programming
2) Coping with the TCP TIME-WAIT state on busy Linux servers https://vincent.bernat.ch/en/blog/2014-tcp-time-wait-state-linux
3) stackoverflow: SO_REUSEADDR vs SO_REUSEPORT

下文中使用的sock程序是从unix networking programming来的,下载地址 https://github.com/unpbook/unpv13e

SO_REUSEADDR和Timewait的关系

  • 即使enable了SO_REUSEADDR,timewait 状态的(src ip, src port, dst ip, dst port) 也不能被connect复用。

证明步骤来自Richard steven Unix network programming 的例子:

  1. 在server上执行 ./sock -s 0.0.0.0 80

  2. 在client 上执行 ./sock 10.0.0.17 80

  3. stop client

观察socket pair 处于tw 状态

tcp        0      0 10.0.0.4:46210          10.0.0.17:80    TIME_WAIT   -
  1. 复用timewait 状态的source port 去连接server,结果失败。
    ./sock -b 46210 10.0.0.17 80bind() error: Address already in use
  1. 使用SO_REUSEADDR, 复用tw 状态的source port 去连接server,结果同样失败。
./sock -A -b 47480 10.0.0.17 80
bind() error: Address already in use
  • Enable 这个选项,使得timewait状态的(src ip, src port)可以bind,否则bind会失败。另外client 能够connect 该地址,从而可能导致timewait 五元祖被复用。这似乎是一个bug。

实验步骤:

  1. 在server上监听80端口, ./sock -s 10.0.0.17 80
  2. 在client上连接server的80端口 ./sock -b 1234 10.0.0.17 80
  3. server 主动断开连接,使得socket 进入timewait状态
  4. server 再次监听, ./sock -s 10.0.0.17 80 结果会失败
./sock  -s 0.0.0.0 80
can't bind local address: Address already in use
  1. server 设置 SO_REUSEADDR, 再次监听,结果成功

./sock -A -s 10.0.0.17 80

有趣的是,上面这个例子中,如果监听的地址是0.0.0.0, 则必须在第一步使用SO_REUSEADDR, 否则会导致第五步./sock -A -s 0.0.0.0 80失败了。

  1. client上执行./sock -b 1234 10.0.0.17 80 成功。timewait的五元组被复用了。 这似乎是一个bug。
tcp        0      0 10.0.0.17:8080          10.0.0.17:1234          TIME_WAIT   -

该timewait的五元组被新的连接复用了。

关于SO_REUSEADDR 其他的行为

在BSD系统中,该option的本意是如果有bind 0.0.0.0:port1的socket, 则其他socket bind 一个具体的local ip:port1可以被允许。但是在linux中,这种行为不被允许。
也就是说wilcard address 和具体的local ip之间有互斥关系。
故这个option在不同的os之间是不兼容的.

实验一:

  1. ./sock -A -s 0.0.0.0 8080

  2. ./sock -A -s 10.0.0.17 8080

结果
can’t bind local address: Address already in use

实验二:

将实验一的步骤反过来

  1. ./sock -A -s 10.0.0.17 8080
  2. ./sock -A -s 0.0.0.0 8080

can’t bind local address: Address already in use

net.ipv4.tcp_tw_reuse

从上文中,我们知道通过设置socket option SO_REUSEADDR, 可以bind 并监听time wait状态的address,这对快速重启server 有很大的帮助,不过对于connect() 复用该地址没有什么作用。这是因为tcp_connect()实现中,对于分配到的port的检查和bind() 不完全一样。为了让connect过程可以快速复用tw port,可以设置内核参数net.ipv4.tcp_tw_reuse.

By enabling net.ipv4.tcp_tw_reuse, Linux will reuse an existing connection in the TIME-WAIT state for a new outgoing connection if the new timestamp is strictly bigger than the most recent timestamp recorded for the previous connection: an outgoing connection in the TIME-WAIT state can be reused after just one second.

更详细的解释请参考
https://vincent.bernat.ch/en/blog/2014-tcp-time-wait-state-linux

实验步骤:

  1. client上

sysctl -w net.ipv4.tcp_tw_reuse=1
sysctl -w net.ipv4.tcp_timestamps=1

  1. server上启动server

./sock -s 0.0.0.0 8080

  1. client上模拟connect耗尽临时端口,使得这些端口都变成timewati状态的。
    再次发起connect,它会复用timewait的port

为了使得测试容易,缩小临时端口的数量。

sysctl -w net.ipv4.ip_local_port_range=“32768 32769”

在client上

a) ./sock 192.168.60.131 8080

b) 退出sock, 32768 port进入tw。

tcp        0      0 192.168.60.133:32768    192.168.60.131:8080     TIME_WAIT   -

c) 再执行 ./sock 192.168.60.131 8080 发现32768 复用了。

tcp        0      0 192.168.60.133:32768    192.168.60.131:8080     ESTABLISHED 3618/./sock

通过bpftrace在内核关键函数加探针,证现tcp_tw_reuse的判断机制发挥了作用。

bpftrace -e 'kretprobe:tcp_twsk_unique{ printf("return %d",retval); }'
Attaching 1 probe...
^Creturn 1

TCP_TW_RECYCLE

该内核参数在4.12以后废弃了。原因是它不仅仅影响了出的报文,还影响了进的报文。如果进的报文是从nat 设备来的,由于不同的host的timestamp 不一致,会导致丢包。

这篇关于Linux tcp timewait相处之道的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1141535

相关文章

Linux脚本(shell)的使用方式

《Linux脚本(shell)的使用方式》:本文主要介绍Linux脚本(shell)的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录概述语法详解数学运算表达式Shell变量变量分类环境变量Shell内部变量自定义变量:定义、赋值自定义变量:引用、修改、删

Linux链表操作方式

《Linux链表操作方式》:本文主要介绍Linux链表操作方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、链表基础概念与内核链表优势二、内核链表结构与宏解析三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势六、典型应用场景七、调试技巧与

详解Linux中常见环境变量的特点与设置

《详解Linux中常见环境变量的特点与设置》环境变量是操作系统和用户设置的一些动态键值对,为运行的程序提供配置信息,理解环境变量对于系统管理、软件开发都很重要,下面小编就为大家详细介绍一下吧... 目录前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变

Linux系统中的firewall-offline-cmd详解(收藏版)

《Linux系统中的firewall-offline-cmd详解(收藏版)》firewall-offline-cmd是firewalld的一个命令行工具,专门设计用于在没有运行firewalld服务的... 目录主要用途基本语法选项1. 状态管理2. 区域管理3. 服务管理4. 端口管理5. ICMP 阻断

Linux实现线程同步的多种方式汇总

《Linux实现线程同步的多种方式汇总》本文详细介绍了Linux下线程同步的多种方法,包括互斥锁、自旋锁、信号量以及它们的使用示例,通过这些同步机制,可以解决线程安全问题,防止资源竞争导致的错误,示例... 目录什么是线程同步?一、互斥锁(单人洗手间规则)适用场景:特点:二、条件变量(咖啡厅取餐系统)工作流

Linux中修改Apache HTTP Server(httpd)默认端口的完整指南

《Linux中修改ApacheHTTPServer(httpd)默认端口的完整指南》ApacheHTTPServer(简称httpd)是Linux系统中最常用的Web服务器之一,本文将详细介绍如何... 目录一、修改 httpd 默认端口的步骤1. 查找 httpd 配置文件路径2. 编辑配置文件3. 保存

Linux使用scp进行远程目录文件复制的详细步骤和示例

《Linux使用scp进行远程目录文件复制的详细步骤和示例》在Linux系统中,scp(安全复制协议)是一个使用SSH(安全外壳协议)进行文件和目录安全传输的命令,它允许在远程主机之间复制文件和目录,... 目录1. 什么是scp?2. 语法3. 示例示例 1: 复制本地目录到远程主机示例 2: 复制远程主

Linux基础命令@grep、wc、管道符的使用详解

《Linux基础命令@grep、wc、管道符的使用详解》:本文主要介绍Linux基础命令@grep、wc、管道符的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录grep概念语法作用演示一演示二演示三,带选项 -nwc概念语法作用wc,不带选项-c,统计字节数-

Linux CPU飙升排查五步法解读

《LinuxCPU飙升排查五步法解读》:本文主要介绍LinuxCPU飙升排查五步法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录排查思路-五步法1. top命令定位应用进程pid2.php top-Hp[pid]定位应用进程对应的线程tid3. printf"%

Linux下安装Anaconda3全过程

《Linux下安装Anaconda3全过程》:本文主要介绍Linux下安装Anaconda3全过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录简介环境下载安装一、找到下载好的文件名为Anaconda3-2018.12-linux-x86_64的安装包二、或者通