【计算机网络】Socket的SO_REUSEADDR选项与TIME_WAIT

SO_REUSEADDR用于设置套接字的地址重用。当一个套接字关闭后,它的端口可能会在一段时间内处于TIME_WAIT状态,此时无法立即再次绑定相同的地址和端口。使用SO_REUSEADDR选项可以允许新的套接字立即绑定到相同的地址和端口,即使之前的套接字仍处于TIME_WAIT状态。

TIME_WAIT状态的产生

客户端和服务器都可以主动发起关闭连接,上图是客户端主动发起的TCP连接关闭。首先调用close()发起主动关闭的一方,在发送最后一个ACK之后会进入time_wait的状态,也就说该发送方会保持2MSL时间之后才会回到初始状态。在time_wait的状态下,定义这个连接的四元组(客户端IP地址和端口,服务端IP地址和端口号)不能被使用。

MSL:Maximum Segment Lifetime,也就是最大报文生存时间 。

MSL到底是多长时间,可以通过下面的命令来查询,不同的操作系统时间不一样:

$ sysctl -a | grep "ipv4.tcp_fin_timeout"
sysctl: unable to open directory "/proc/sys/fs/binfmt_misc/"
net.ipv4.tcp_fin_timeout = 60

time_wait至少需要持续2MSL时长,这2个MSL中的第一个MSL是为了等自己发出去的最后一个ACK从网络中消失,而第二MSL是为了等在对端收到ACK之前的一刹那可能重传的FIN报文从网络中消失。如果time_wait时间是一个MSL,而time_wait结束后使用了相同的IP和Port建立了新的TCP连接,由于旧连接重传的FIN报文还没有在网络中消失,因此会干扰到新的TCP连接。

SO_REUSEADDR的使用

可以使用Socket类的setReuseAddress()方法来设置SO_REUSEADDR选项的值。示例代码如下:

ServerSocket serverSocket1 = new ServerSocket();
serverSocket1.setReuseAddress(false);
serverSocket1.bind(new InetSocketAddress(8099));
serverSocket1.close();

使用SO_REUSEADDR选项时有两点需要注意:

  1. 必须在调用bind方法之前使用setReuseAddress方法来打开SO_REUSEADDR选项。因此,要想使用SO_REUSEADDR选项,就不能通过Socket类的构造方法来绑定端口。

  2. 必须将绑定同一个端口的所有的Socket对象的SO_REUSEADDR选项都打开才能起作用。

SO_REUSEADDR异常的演示

Socket服务端代码如下:

package com.morris.socket;import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;/*** Socket客户端,演示SO_REUSEADDR** @see java.net.SocketOptions*/
public class ReuseAddressServerDemo {public static void main(String[] args) throws IOException {ServerSocket serverSocket1 = new ServerSocket();System.out.println(serverSocket1.getReuseAddress());// serverSocket1.setReuseAddress(false);serverSocket1.bind(new InetSocketAddress(8099));Socket socket = serverSocket1.accept();socket.getOutputStream().write("hello".getBytes(StandardCharsets.UTF_8));socket.close();}
}

Socket客户端代码如下:

package com.morris.socket;import java.io.IOException;
import java.net.Socket;/*** Socket客户端,演示SO_REUSEADDR** @see java.net.SocketOptions*/
public class ReuseAddressClientDemo {public static void main(String[] args) throws IOException {// 这里只建立连接,不发送数据,也不接受数据,也不关闭连接,这样服务端才会出现TIME_WAITnew Socket("172.24.104.61", 8099);System.in.read();}
}

当客户端与服务端建立连接后,服务端发完数据就会立即关闭,此时会进入TIME_WAIT状态:

$ netstat -anotp| grep 8099
tcp6       0      0 172.24.104.61:8099      172.24.104.61:54542     FIN_WAIT2   -                    timewait (57.97/0/0)

我们可以看到四元组172.24.104.61:8099,172.24.104.61:54542代表的这个链接已经进入FIN_WAIT2状态,而且还需要等待57.97s才能进入CLOSE状态。

SO_REUSEADDR选项为true,也就是serverSocket1.setReuseAddress(true),也可以不进行设置,因为默认就是true,允许地址重用,此时再次启动ReuseAddressServerDemo程序,能够成功启动不会抛出端口被占用的异常。

SO_REUSEADDR选项为false,也就是serverSocket1.setReuseAddress(false),不允许地址重用,此时再次启动ReuseAddressServerDemo程序,就会抛出下面的异常:

Exception in thread "main" java.net.BindException: Address already in useat java.base/sun.nio.ch.Net.bind0(Native Method)at java.base/sun.nio.ch.Net.bind(Net.java:555)at java.base/sun.nio.ch.Net.bind(Net.java:544)at java.base/sun.nio.ch.NioSocketImpl.bind(NioSocketImpl.java:640)at java.base/java.net.ServerSocket.bind(ServerSocket.java:392)at java.base/java.net.ServerSocket.bind(ServerSocket.java:340)at com.morris.socket.ReuseAddressServerDemo.main(ReuseAddressServerDemo.java:20)

这时只有等四元组172.24.104.61:8099,172.24.104.61:54542代表的这个链接进入CLOSE状态后才能再次启动ReuseAddressServerDemo程序。

SO_REUSEADDR的注意事项与使用场景

在使用SO_REUSEADDR选项时,需要注意以下几点:

  • SO_REUSEADDR选项必须在调用bind()函数之前设置,否则设置不会生效。

  • 在使用SO_REUSEADDR选项时,需要确保不同的套接字使用相同的协议、地址和端口组合。

  • 使用SO_REUSEADDR选项不能使不同的线程或进程监听相同的端口,实现端口服用。

使用场景:

  • 服务器程序重启:当服务器程序需要重启时,为了避免等待操作系统回收端口的时间,可以设置SO_REUSEADDR选项。这样,重启后的服务器程序可以快速绑定到之前使用的端口上,实现快速恢复服务。

  • 测试和调试:在开发和测试阶段,可能需要频繁地启动和停止服务器。使用SO_REUSEADDR可以使得测试更加方便,因为不需要担心地址和端口已经被其他进程使用的问题。

time_wait产生的危害以及如何解决

大量的time_wait产生需要的条件:

  • 高并发

  • 服务器主动关闭连接

如果服务器不主动关闭连接,那么TIME_WAIT就是客户端的事情了

在高并发短连接的TCP服务器上,当服务器处理完请求后立刻主动正常关闭连接。这个场景下会出现大量socket处于time_wait状态。在time_wait的状态下,定义这个连接的四元组(客户端IP地址和端口,服务端IP地址和端口号)不能被使用。因此,高并发可以让服务器在短时间范围内同时占用大量端口。如果客户端的并发量持续很高,此时部分客户端就会因为端口已经被占用而显示连接不上。

如何解决大量time_wait产生的危害?

  • 调整优化linux内核参数:出现大量TIME_WAIT的情况,一般是服务端没有及时回收端口,可以缩减time_wait时间。

  • 服务器不主动关闭连接

  • 重用端口:设置套接字选项为SO_REUSEADDR,告诉操作系统,如果端口忙,但占用该端口TCP连接处于TIME_WAIT状态,则该端口可被重用。如果TCP连接处于其他状态,依然返回端口被占用。该选项对服务程序重启非常有用。

  • 使用长连接:HTTP请求的头部,connection设置为keep-alive

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/661982.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vim实战:使用Vim实现图像分类任务(一)

文章目录 摘要安装包安装timm 数据增强Cutout和MixupEMA项目结构编译安装Vim环境环境安装过程安装库文件 计算mean和std生成数据集 摘要 论文:https://arxiv.org/pdf/2401.09417v1.pdf 翻译: 近年来,随着深度学习的发展,视觉模型…

JUC并发编程01——进程,线程(详解),并发和并行

目录 1.进程和线程的概念及对比1.进程概述 2.线程3.对比 2.并行与并发1.并发2.并行 3.线程详解3.1.创建和运行线程3.1.1.Thread3.1.2.Runnable结合Thread 创建线程3.1.3.Callable 3.2线程方法APIrun startsleep yieldjoininterrupt打断线程打断 park终止模式 daemon不推荐使用的…

基于Java SSM框架实现校园快领服务系统项目【项目源码+论文说明】计算机毕业设计

基于java的SSM框架实现校园快领服务系统演示 摘要 随着科学技术的飞速发展,各行各业都在努力与现代先进技术接轨,通过科技手段提高自身的优势;对于校园快领服务系统当然也不能排除在外,随着网络技术的不断成熟,带动了…

骨传导耳机的技术原理是什么?和传统耳机相比有哪些优点?

骨传导耳机通过人体骨骼来传递声音,可以绕过耳道和耳膜直接传达音频到听者的内耳,开放双耳的佩戴方式可以在享受音乐或通话的同时保持对周围环境的感知,这种设计在户外活动或运动等场景下的使用尤为实用,可以避免堵塞耳朵&#xf…

CHS_08.2.3.6_1+生产者-消费者问题

CHS_08.2.3.6_1生产者-消费者问题 问题描述问题分析思考:能否改变相邻P、V操作的顺序?知识回顾 在这个小节中 我们会学习一个经典的进程同步互斥的问题 问题描述 并且尝试用上个小节学习的p v操作 也就是信号量机制来解决这个生产者消费者问题 问题的描…

大力说视频号第三课:视频小店

自从腾讯推出视频号之后,大家非常明显的感觉到,视频号正以势不可挡的姿势走向独立发展。那么,依托于微信生态的视频号,未来将迎来哪些精彩发展呢? 让我们一同来揭开“视频号小店”的神秘面纱,了解一下玩法…

有色金属矿山采选智能工厂数字孪生可视化,推进矿采选业数字化转型

有色金属矿山采选智能工厂数字孪生可视化,推进矿采选业数字化转型。随着科技的不断发展,数字化转型已经成为各行各业发展的必然趋势。有色金属矿采选业作为传统工业的重要组成部分,也面临着数字化转型的挑战。为了更好地推进有色金属矿采选业…

百无聊赖之JavaEE从入门到放弃(十七)时间处理相关类

目录 一.Date 时间类 二.DateFormat 类和 SimpleDateFormat 类 三.Calendar 日历类 “时间如流水,一去不复返”,时间是一维的。所以,我们需要一把刻度尺来表达和度 量时间。在计算机世界,我们把 1970 年 1 月 1 日 00:00:00 定…

张维迎《博弈与社会》多重均衡与制度和文化(4)路径依赖的困惑

在前述计算机产品标准化的问题中,有两个纳什均衡:都生产有5.25英寸软盘驱动器的计算机和都生产有3.5英寸软盘驱动器的计算机。假设一开始企业只能生产有5.25英寸软盘驱动器的计算机,生产3.5英寸软盘驱动器计算机的技术随后出现,企…

Next.js如何正确处理跨域问题?

以前一直使用Vue来写前端。去年下半年接手了一个基于React Next.js的项目,于是顺带学习了一下Next.js。由于Next.js的特点,这个项目的前后端是放在一起的。一开始没什么问题,看了半天文档就上手了。 上周我们需要在另一个网页项目中&#x…

C#,桌面游戏编程,数独游戏(Sudoku Game)的算法与源代码

本文包括以下内容: (1)数独游戏的核心算法; (2)数独游戏核心算法的源代码; (3)数独游戏的部分题目样本; (4)适老版《数独》的设计原则…

C#,哥伦布数(Golomb Number)的算法与源代码

1 哥伦布数(Golomb Number) 哥伦布数(Golomb Number)是一个自然数的非减量序列,使得n在序列中正好出现G(n)次。前几个15的G(n)值为:1 2 2 3 3 4 4 4 5 5 5 6…

计算机图形学 实验

题目要求 1.1 实验一:图元的生成:直线、圆椭区域填充 你需要完成基本的图元生成算法,包括直线和椭圆。 在区域填充中,要求你对一个封闭图形进行填充。你需要绘制一个封 闭图形(例如多边形),并选…

Hadoop3.x基础(3)- MapReduce

来源: B站尚硅谷 目录 MapReduce概述MapReduce定义MapReduce优缺点优点缺点 MapReduce核心思想MapReduce进程常用数据序列化类型MapReduce编程规范WordCount案例实操本地测试提交到集群测试 Hadoop序列化序列化概述自定义bean对象实现序列化接口(Writable&#xff…

新手不会Git也能玩Github吗?

新手不会Git也能玩Github吗? 前言使用Github的准备步骤使用一种访问外网资源的方法(这一步才是新手最容易)注册账号 创建一个自己的仓库创建完仓库后的界面 搜索你想要的代码类型以搜索坦克大战为例以下载烟花代码为例 总结 前言 说到Github&…

人工智能福利站,初识人工智能,机器学习,第四课

🏆作者简介,普修罗双战士,一直追求不断学习和成长,在技术的道路上持续探索和实践。 🏆多年互联网行业从业经验,历任核心研发工程师,项目技术负责人。 🎉欢迎 👍点赞✍评论…

我已经入驻多多

我已经入驻多多面包多平台 啦! 作为一位专注于帮助人们部署Python环境、探索人工智能和JavaEE技术,并创作计算机课程设计相关作品的创作者。我的作品类型涵盖了各种技术领域,旨在为学习者提供实用的资源和指导。 在CSDN拥有1100个粉丝的基础上&#x…

arcgis javascript api4.x加载非公开或者私有的arcgis地图服务

需求: 加载arcgis没有公开或者私有的地图服务,同时还想实现加载时不弹出登录窗口 提示:​ 下述是针对独立的arcgis server,没有portal的应用场景; 如果有portal可以参考链接:https://mp.weixin.qq.com/s/W…

MapStruct 使用

MapStruct最详细的使用教程,别在用BeanUtils.copyProperties () mapstruct使用和详解 项目背景 之前查看网上别人写的文章,很多都提到了BeanUtils(org.springframework.beans) 利用反射性能比较差。大家都推荐使用 MapStruct。因为这个组件使用 Java 原…

zookeeper 应该这样学

ZooKeeper 是一个分布式的,开放源码的分布式应用程序协调服务,是 Google 的 Chubby 一个开源的实现,是 Hadoop 和 Hbase 的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分…