当前位置: 首页 > news >正文

【计算机网络】Socket的SO_TIMEOUT与连接超时时间

SO_TIMEOUT选项是Socket的一个选项,用于设置读取数据的超时时间。它指定了在读取数据时等待的最长时间,如果在指定的时间内没有数据可读取,将抛出SocketTimeoutException异常。

SO_TIMEOUT的设置

默认情况下,SO_TIMEOUT选项的值为0,表示没有设置超时时间,Socket将一直阻塞等待数据的到达。如果将SO_TIMEOUT的值设置为一个非零的正整数,那么在读取数据时,如果在指定的时间内没有数据可读取,将抛出SocketTimeoutException异常。

可以通过Socket类的setSoTimeout()方法来设置SO_TIMEOUT选项的值,例如:

package com.morris.socket;import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;/*** Socket服务端,演示SO_TIMEOUT** 客户端可以使用nc命令*/
public class ReadTimeoutDemo {public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(8099);Socket socket = serverSocket.accept();socket.setSoTimeout(5000); // 设置超时时间为5秒InputStream inputStream = socket.getInputStream();try {byte[] buffer = new byte[1024];int len = inputStream.read(buffer);System.out.println(new String(buffer, 0 , len));} catch (Exception e) {System.out.println(e.getMessage());byte[] buffer = new byte[1024];int len = inputStream.read(buffer);System.out.println(new String(buffer, 0 , len));socket.close();serverSocket.close();}}
}

上面的例子中设置了SO_TIMEOUT的值为5000,单位为毫秒,也就是设置了读取数据的超时时间为5秒,如果在5秒内没有数据可读取,将抛出SocketTimeoutException异常,可以通过捕获这个异常来处理超时情况。

注意超时了只是会抛出了SocketTimeoutException异常,read()方法不再阻塞,连接并没有关闭,可以通过捕获这个异常后继续读取数据,或者关闭连接。

产生的系统调用如下:

socket(AF_INET6, SOCK_STREAM, IPPROTO_IP) = 4
setsockopt(4, SOL_IPV6, IPV6_V6ONLY, [0], 4) = 0
setsockopt(4, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
bind(4, {sa_family=AF_INET6, sin6_port=htons(8099), sin6_flowinfo=htonl(0), inet_pton(AF_INET6, "::", &sin6_addr), sin6_scope_id=0}, 28) = 0
listen(4, 50)
accept(4, {sa_family=AF_INET6, sin6_port=htons(44964), sin6_flowinfo=htonl(0), inet_pton(AF_INET6, "::ffff:127.0.0.1", &sin6_addr), sin6_scope_id=0}, [28]) = 5
read(5, 0x7f586012c6c0, 1024)           = -1 EAGAIN (Resource temporarily unavailable)
poll([{fd=5, events=POLLIN}], 1, 4935)  = 0 (Timeout)
read(5, 0x7f586012c6c0, 1024)           = -1 EAGAIN (Resource temporarily unavailable)

可以看到底层是使用poll的timeout参数来实现读取超时时间的设置。

poll的函数声明如下:

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

设置连接超时时间

前面的代码通过SO_TIMEOUT选项来设置数据读取的超时时间,那么Socket之间建立连接的超时时间如何设置呢?

客户端建立连接时可以使用connect()来指定连接的超时时间:

package com.morris.socket;import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;/*** Socket客户端,演示连接超时时间**/
public class ConnectTimeoutClientDemo {public static void main(String[] args) throws IOException {Socket socket = new Socket();socket.connect(new InetSocketAddress("localhost", 8099), 5000);}
}

在上述代码中,通过调用Socket的connect()方法来尝试连接服务器,并设置连接超时时间为5秒。如果在5秒内未能成功连接到服务器,将抛出SocketTimeoutException异常。

客户端产生的系统调用如下:

socket(AF_INET6, SOCK_STREAM, IPPROTO_IP) = 4
setsockopt(4, SOL_IPV6, IPV6_V6ONLY, [0], 4) = 0
fcntl(4, F_GETFL)                       = 0x2 (flags O_RDWR)
fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK)    = 0
connect(4, {sa_family=AF_INET6, sin6_port=htons(8099), sin6_flowinfo=htonl(0), inet_pton(AF_INET6, "::ffff:127.0.0.1", &sin6_addr), sin6_scope_id=0}, 28) = -1 EINPROGRESS (Operation now in progress)
poll([{fd=4, events=POLLOUT}], 1, 0)    = 0 (Timeout)
clock_gettime(CLOCK_MONOTONIC, {tv_sec=10284, tv_nsec=286532200}) = 0
poll([{fd=4, events=POLLOUT}], 1, 4893) = 0 (Timeout)
poll([{fd=4, events=POLLOUT}], 1, 0)    = 0 (Timeout)

可以看到客户端的连接超时时间也是通过poll函数的timeout来实现的。

服务端可以下面的代码来演示抛出SocketTimeoutException异常:

package com.morris.socket;import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;/*** Socket服务端,演示连接超时时间** 使用nc命令执行两次后,再执行ConnectTimeoutClientDemo,这样就会抛出SocketTimeoutException*/
public class ConnectTimeoutServerDemo {public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket();serverSocket.bind(new InetSocketAddress(8099), 1);System.in.read();}
}

先使用nc命令执行两次消耗backlog的值,然后再ConnectTimeoutClientDemo,5s后就会抛出SocketTimeoutException。

默认连接超时时间

如果不设置连接超时时间,默认值是多少呢,会不会像读取超时时间一样一直等待呢?

我们可以使用下面的代码来测试默认的连接超时时间是多长:

package com.morris.socket;import java.io.IOException;
import java.net.Socket;/*** Socket客户端,演示连接超时时间**/
public class DefaultConnectTimeoutClientDemo {public static void main(String[] args) throws IOException {long start = System.currentTimeMillis();try {new Socket("localhost", 8099);} catch (Exception e) {e.printStackTrace();}System.out.println("cost: " + (System.currentTimeMillis() - start));}
}

同样配合ConnectTimeoutServerDemo和nc命令使用,运行结果如下:

java.net.ConnectException: Connection timed outat java.base/sun.nio.ch.Net.connect0(Native Method)at java.base/sun.nio.ch.Net.connect(Net.java:579)at java.base/sun.nio.ch.Net.connect(Net.java:568)at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:585)at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327)at java.base/java.net.Socket.connect(Socket.java:633)at java.base/java.net.Socket.connect(Socket.java:583)at java.base/java.net.Socket.<init>(Socket.java:507)at java.base/java.net.Socket.<init>(Socket.java:287)at com.morris.socket.DefaultConnectTimeoutClientDemo.main(DefaultConnectTimeoutClientDemo.java:14)
cost: 135866

可以看出整个过程花费了135秒,这个时间是怎么得来的呢?

client发送sync包,可能会在网络链路中丢失,也有可能server端因为各种原因未及时处理或者无法处理,则client要进行重新发送sync包,而这重试的次数就是由net.ipv4.tcp_syn_retries来决定,默认是6。第一次发送sync包,会进行1s的超时等待,第二次发送sync包,会进行2s的超市等待,如此类推,公式是2的N次方。

查看net.ipv4.tcp_syn_retries的值:

$ sysctl -a | grep net.ipv4.tcp_syn_retries
net.ipv4.tcp_syn_retries = 6

抓包数据:

$ tcpdump -nn -i lo port 8099
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
11:44:02.238833 IP 127.0.0.1.53222 > 127.0.0.1.8099: Flags [S], seq 319321421, win 65495, options [mss 65495,sackOK,TS val 2026768840 ecr 0,nop,wscale 7], length 0
11:44:03.259673 IP 127.0.0.1.53222 > 127.0.0.1.8099: Flags [S], seq 319321421, win 65495, options [mss 65495,sackOK,TS val 2026769860 ecr 0,nop,wscale 7], length 0
11:44:05.329576 IP 127.0.0.1.53222 > 127.0.0.1.8099: Flags [S], seq 319321421, win 65495, options [mss 65495,sackOK,TS val 2026771930 ecr 0,nop,wscale 7], length 0
11:44:09.409633 IP 127.0.0.1.53222 > 127.0.0.1.8099: Flags [S], seq 319321421, win 65495, options [mss 65495,sackOK,TS val 2026776010 ecr 0,nop,wscale 7], length 0
11:44:17.489597 IP 127.0.0.1.53222 > 127.0.0.1.8099: Flags [S], seq 319321421, win 65495, options [mss 65495,sackOK,TS val 2026784090 ecr 0,nop,wscale 7], length 0
11:44:34.129690 IP 127.0.0.1.53222 > 127.0.0.1.8099: Flags [S], seq 319321421, win 65495, options [mss 65495,sackOK,TS val 2026800730 ecr 0,nop,wscale 7], length 0
11:45:06.769597 IP 127.0.0.1.53222 > 127.0.0.1.8099: Flags [S], seq 319321421, win 65495, options [mss 65495,sackOK,TS val 2026833370 ecr 0,nop,wscale 7], length 0

HttpClient的超时时间与Socket的超时时间的关系

以下是使用HttpClient设置超时时间的示例:

package com.morris.socket;import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;import java.io.IOException;/*** 验证HttpClient的超时时间与Socket超时时间的关系*/
public class HttpClientTimeoutDemo {public static void main(String[] args) throws IOException {// 创建 RequestConfig 实例,并设置超时时间RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(5000) // 连接超时时间,单位毫秒.setSocketTimeout(5000) // 读取超时时间,单位毫秒.build();// 将超时配置应用到 HttpClient 实例CloseableHttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(requestConfig).build();HttpGet httpGet = new HttpGet("http://localhost:8099");httpClient.execute(httpGet);}
}

在上述示例中,setConnectTimeout设置了连接超时时间,即建立连接的最长等待时间。setSocketTimeout设置了读取超时时间,即从服务器读取数据的最长等待时间。

产生的系统调用如下:

socket(AF_INET6, SOCK_STREAM, IPPROTO_IP) = 10
connect(10, {sa_family=AF_INET6, sin6_port=htons(8099), sin6_flowinfo=htonl(0), inet_pton(AF_INET6, "::ffff:127.0.0.1", &sin6_addr), sin6_scope_id=0}, 28) = -1 EINPROGRESS (Operation now in progress)
poll([{fd=10, events=POLLOUT}], 1, 4922) = 0 (Timeout)

从系统调用中可以看到,在应用层httpclient设置的超时时间实际上对应的是底层socket的超时时间。

在使用HttpClient发起HTTP请求时,可以通过设置超时时间来控制连接、读取和写入的超时行为。超时时间可以确保请求在合理的时间范围内完成,避免长时间等待或无限期阻塞。

相关文章:

【计算机网络】Socket的SO_TIMEOUT与连接超时时间

SO_TIMEOUT选项是Socket的一个选项&#xff0c;用于设置读取数据的超时时间。它指定了在读取数据时等待的最长时间&#xff0c;如果在指定的时间内没有数据可读取&#xff0c;将抛出SocketTimeoutException异常。 SO_TIMEOUT的设置 默认情况下&#xff0c;SO_TIMEOUT选项的值…...

解密 ARMS 持续剖析:如何用一个全新视角洞察应用的性能瓶颈?

作者&#xff1a;饶子昊、杨龙 应用复杂度提升&#xff0c;根因定位困难重重 随着软件技术发展迭代&#xff0c;很多企业软件系统也逐步从单体应用向云原生微服务架构演进&#xff0c;一方面让应用实现高并发、易扩展、开发敏捷度高等效果&#xff0c;但另外一方面也让软件应…...

【OJ比赛日历】春节快乐 #02.10-02.16 #9场

CompHub[1] 实时聚合多平台的数据类(Kaggle、天池…)和OJ类(Leetcode、牛客…&#xff09;比赛。本账号会推送最新的比赛消息&#xff0c;欢迎关注&#xff01; 以下信息仅供参考&#xff0c;以比赛官网为准 目录 2024-02-10&#xff08;周六&#xff09; #4场比赛2024-02-11…...

前端下载文件有哪些方式

前端下载文件有哪些方式 在前端&#xff0c;最常见和最常用的文件下载方式是&#xff1a; 使用 标签的 download 属性&#xff1a; 创建一个 标签&#xff0c;并设置其 href 属性为文件的 URL&#xff0c;然后使用 download 属性指定下载的文件名。 这种方式简单直接&…...

vscode预览github上的markdown效果

需要安装的插件有&#xff1a; Github Markdown Preview Markdown Checkboxes Markdown Emoji Markdown footnotes Markdown Preview Github Styling Markdown Preview Mermaid Support Markdown yaml Preamble ctrlshiftv结合双页功能...

使用PaddleNLP识别垃圾邮件:用BERT做中文邮件内容分类,验证集准确率高达99.6%以上(附公开数据集)

使用PaddleNLP识别垃圾邮件:用BERT做中文邮件内容分类,验证集准确率高达99.6%以上(附公开数据集)。 要使用PaddleNLP和BERT来识别垃圾邮件并做中文邮件内容分类,可以按照以下步骤进行操作: 安装PaddlePaddle和PaddleNLP:首先,确保在你的环境中已经安装了PaddlePaddle和…...

在bash或脚本中,如何并行执行命令或任务(命令行、parallel、make)

最近要批量解压归档文件和压缩包&#xff0c;所以就想能不能并行执行这些工作。因为tar自身不支持并行解压&#xff0c;但是像make却可以支持生成一些文件&#xff0c;所以我才有了这种想法。 方法有两种&#xff0c;第一种不用安装任何软件或工具&#xff0c;直接bash或其他 …...

拼音笔记笔记

一、翀的读音&#xff1a;chōng 声母&#xff1a;ch 韵母&#xff1a;ong 声调&#xff1a;一声 二、汉字释义&#xff1a; 向上直飞&#xff0c;相当于“冲”。 三、汉字结构&#xff1a;左右结构 四、部首&#xff1a;羽 五、相关词组&#xff1a; 翀举&#xff1a;谓成仙升…...

13. Threejs案例-绘制3D文字

13. Threejs案例-绘制3D文字 实现效果 知识点 FontLoader 一个用于加载 JSON 格式的字体的类。 返回 font&#xff0c;返回值是表示字体的 Shape 类型的数组。 其内部使用 FileLoader 来加载文件。 构造器 FontLoader( manager : LoadingManager ) 参数类型描述managerLo…...

clickhouse清理日志。

参考Clickhouse&#xff1a;日志表占用大量磁盘空间怎么办&#xff1f;_clickhouse store目录很大-CSDN博客t 清理脚本如下&#xff0c;清理动作需要时间比较长&#xff0c;10多分钟&#xff1a; alter table system.trace_log delete where event_date < 2024-01-01 alt…...

JS中实现继承

1.使用call实现继承&#xff08;不推荐&#xff09; function Animal(name) {this.name name;this.run function() {console.log(this.name, "跑");} } function Dog(name) {// 继承Animal.call(this, name);this.sleep function() {console.log(this.name, &quo…...

spring boot学习第九篇:操作mongo的集合和集合中的数据

1、安装好了Mongodb 参考&#xff1a;ubuntu安装mongod、配置用户访问、添删改查-CSDN博客 2、pom.xml文件内容如下&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns…...

momentJs推导日历组件

实现效果: 代码&#xff1a; 引入momentjs然后封装两个函数构建出基本数据结构 import moment from moment;// 某月有多少天 export const getEndDay (m) > m.daysInMonth();/*** description 获取本月空值数据* param { Date } year { } 年度* param { Number } month …...

Linux C/C++ 原始套接字:打造链路层ping实现

在C/C中&#xff0c;我们可以使用socket函数来创建套接字。我们需要指定地址族为AF_PACKET&#xff0c;协议为htons(ETH_P_ALL)来捕获所有传入和传出的数据包。 可以使用sendto和recvfrom函数来发送和接收数据包。我们需要构建一个合法的链路层数据包&#xff0c;在数据包的头…...

TCP 粘包/拆包

文章目录 概述粘包拆包发生场景解决TCP粘包和拆包问题的常见方法Netty对粘包和拆包问题的处理小结 概述 TCP的粘包和拆包问题往往出现在基于TCP协议的通讯中&#xff0c;比如RPC框架、Netty等 TCP 粘包/拆包 就是你基于 TCP 发送数据的时候&#xff0c;出现了多个字符串“粘”…...

【Spring Boot 3】应用启动执行特定逻辑

【Spring Boot 3】应用启动执行特定逻辑 背景介绍开发环境开发步骤及源码工程目录结构总结背景 软件开发是一门实践性科学,对大多数人来说,学习一种新技术不是一开始就去深究其原理,而是先从做出一个可工作的DEMO入手。但在我个人学习和工作经历中,每次学习新技术总是要花…...

设计模式(行为型模式)观察者模式

目录 一、简介二、观察者模式2.1、事件接口及其实现2.2、观察者接口及其实现2.3、主题接口及其实现2.4、使用 三、优点与缺点 一、简介 观察者模式&#xff08;Observer Pattern&#xff09;是一种行为设计模式&#xff0c;它定义了一种一对多的依赖关系&#xff0c;当一个对象…...

Windows 版Oracle 数据库(安装)详细过程

首先到官网上去下载oracle64位的安装程序 第一步&#xff1a;将两个datebase文件夹解压到同一目录中。 当下载完成后,它里面是两个文件夹 win64_11gR2_database_1of2, win64_11gR2_database_2of2,我们需要把其中的一个database文件夹整合在一起(复制一个database文件夹到另一…...

编程实例分享,计费系统一定要安装灯光控制吗?佳易王计时计费管理系统软件V18.0教程说明

编程实例分享&#xff0c;计费系统一定要安装灯光控制吗&#xff1f;佳易王计时计费管理系统软件V18.0教程说明 一、前言 以下教程以 佳易王计时计费软件V18.0为例说明 1、该软件既可以接灯控&#xff0c;也可以不接灯控&#xff0c;如果接灯控&#xff0c;则点击开始计时的时…...

【webpack】优化提升

webpack优化提升 安装webpack相关内容向下兼容游览器-babel/polyfill进一步优化babel/polyfill模块联邦-共享模块如何提升构建性能通用环境下1&#xff0c;webpack更新到最新版本2&#xff0c;将loader应用于最少数量的必要模块3&#xff0c;引导&#xff08;每个额外的loader/…...

汽车生产虚拟实训中的技能提升与生产优化​

在制造业蓬勃发展的大背景下&#xff0c;虚拟教学实训宛如一颗璀璨的新星&#xff0c;正发挥着不可或缺且日益凸显的关键作用&#xff0c;源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例&#xff0c;汽车生产线上各类…...

linux 错误码总结

1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”

目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

Linux离线(zip方式)安装docker

目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1&#xff1a;修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本&#xff1a;CentOS 7 64位 内核版本&#xff1a;3.10.0 相关命令&#xff1a; uname -rcat /etc/os-rele…...

JS设计模式(4):观察者模式

JS设计模式(4):观察者模式 一、引入 在开发中&#xff0c;我们经常会遇到这样的场景&#xff1a;一个对象的状态变化需要自动通知其他对象&#xff0c;比如&#xff1a; 电商平台中&#xff0c;商品库存变化时需要通知所有订阅该商品的用户&#xff1b;新闻网站中&#xff0…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生&#xff0c;小白用户&#xff0c;想学习知识的 有点基础&#xff0c;想要通过项…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

Golang——7、包与接口详解

包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...

【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅

目录 前言 操作系统与驱动程序 是什么&#xff0c;为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中&#xff0c;我们在使用电子设备时&#xff0c;我们所输入执行的每一条指令最终大多都会作用到硬件上&#xff0c;比如下载一款软件最终会下载到硬盘上&am…...

【堆垛策略】设计方法

堆垛策略的设计是积木堆叠系统的核心&#xff0c;直接影响堆叠的稳定性、效率和容错能力。以下是分层次的堆垛策略设计方法&#xff0c;涵盖基础规则、优化算法和容错机制&#xff1a; 1. 基础堆垛规则 (1) 物理稳定性优先 重心原则&#xff1a; 大尺寸/重量积木在下&#xf…...