【计算机网络】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 out
        at 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请求时,可以通过设置超时时间来控制连接、读取和写入的超时行为。超时时间可以确保请求在合理的时间范围内完成,避免长时间等待或无限期阻塞。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

引入echarts环形图及显示后端数据

实现效果&#xff1a; 1.下载echarts 并引用 npm install echarts --save 或 pnpm install -S echarts 项目中引用&#xff1a; 在项目main.ts中 import * as echarts from "echarts"; //引入echarts 3.页面中使用 <div id"main" class&quo…

近屿智能发布AIGC大模型工程师和产品经理学习路径图

近日&#xff0c;上海近屿智能科技有限公司&#xff08;下称“近屿智能”&#xff09;&#xff0c;基于其在大模型研发和产品设计领域深厚的专业积累&#xff0c;终于总结出AIGC大模型工程师与产品经理的学习路线图。该学习路线图不仅为追求专业发展的学习者提供了一条清晰明确…

从[redis:LinkedList]中学习链表

文章目录 adlistlistNodelistmacros[宏定义]listCreatelistInitNodelistEmptylistReleaselistAddNodeHeadlistLinkNodeHeadlistAddNodeTaillistLinkNodeTaillistInsertNodelistDelNodelistUlinkNodelistIndexredis3.2.100quicklistredis7.2.2quicklist redis的基本数据类型之一…

TTime翻译软件下载使用教程~~

简介 TTime是一款翻译软件&#xff0c;主要功能为输入翻译、截图翻译、划词翻译 平时工作或学习中难免会有存在需要翻译的场景&#xff0c;但是又没有一款好用而又简单的翻译工具 为此TTime出现了&#xff0c;它可以帮助我们更好的提高工作和学习效率 下载安装及使用教程 跳转…

【C语言 - 哈希表 - 力扣 - 相交链表】

相交链表题目描述 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据 保证 整个链式结构中不存在环。 注意&#xff0…

希望你用不上这篇文章!

每年的调剂信息非常重要。可以说是成绩不太理想的同学&#xff0c;最后一根救命稻草&#xff01;这篇文章很重要&#xff0c;但希望你用不上&#xff01; 调剂是一场信息战。注意&#xff01;千万不要轻信哪个学校容易调剂的建议。今天就给大家详细讲讲关于调剂的全流程。请耐…

验证码倒计时:用户界面的小细节,大智慧

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 验证码倒计时&#xff1a;用户界面的小细节&#xff0c;大智慧 前言为什么需要验证码倒计时防止滥用&#xff1a;用户心理&#xff1a; 设计考量可见性&#xff1a;友好性&#xff1a;适应性&#xff…

2023年全球软件架构师峰会(ArchSummit上海站):核心内容与学习收获(附大会核心PPT下载)

微服务架构是当今软件架构的主流趋势之一。随着云计算和分布式系统的普及&#xff0c;越来越多的企业开始采用微服务架构来构建他们的应用。微服务架构可以将一个大型的应用拆分成多个小型的服务&#xff0c;每个服务都独立部署、独立运行&#xff0c;并通过轻量级的通信协议进…

【Boost】:阶段性测试和阶段性代码合集(五)

阶段性测试和阶段性代码合集 一.编写测试程序-server.cc二.一些问题三.完整源代码 在这里添加了一些打印信息&#xff0c;方便我们观察&#xff0c;由于比较分散就不一一列举&#xff0c;可以看下面的完整源代码。 一.编写测试程序-server.cc 1.原版 只是简单的测试&#xff0…

如何有效的开展接口自动化测试(超详细整理)

一、简介 接口自动化测试是指使用自动化测试工具和脚本对软件系统中的接口进行测试的过程。其目的是在软件开发过程中&#xff0c;通过对接口的自动化测试来提高测试效率和测试质量&#xff0c;减少人工测试的工作量和测试成本&#xff0c;并且能够快速发现和修复接口错误&…

视频业务像素、带宽、存储空间计算

一、像素和分辨率 分辨率的单位通常是像素&#xff08;或点&#xff09;&#xff0c;用水平像素数乘以垂直像素数来表示。例如&#xff0c;一个分辨率为1920 x 1080的屏幕有1920个水平像素和1080个垂直像素。 总像素分辨率公式运算 例如 1920 x 10802073600总约200万 500W≈…

【05_发送测试报告到邮箱】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 05_发送测试报告到邮箱 1、获取邮箱授权码2、构造附件3、发送邮件4、完整示例 测试报告生成后&#xff0c;可以将报告发送至开发、测试邮箱&#xff0c;以便查看测试报告详情…

爬虫实战--爬取简单文字图片并保存到mongodb数据库

文章目录 前言发现宝藏 前言 为了巩固所学的知识&#xff0c;作者尝试着开始发布一些学习笔记类的博客&#xff0c;方便日后回顾。当然&#xff0c;如果能帮到一些萌新进行新技术的学习那也是极好的。作者菜菜一枚&#xff0c;文章中如果有记录错误&#xff0c;欢迎读者朋友们…

基于ESP8266 开发板(MCU)遥控小车

遥控小车 ​ 遥控界面 ​ 【项目源码】 第一版ESP8266 https://github.com/liyinchigithub/esp8266_car_webServerhttps://github.com/liyinchigithub/esp8266_car_webServer 第二版ESP32 GitHub - liyinchigithub/esp32-wroom-car: 嵌入式单片机 ESP32 Arduino 遥控小车&a…

《Python 网络爬虫简易速速上手小册》第7章:如何绕过反爬虫技术?(2024 最新版)

文章目录 7.1 识别和应对 CAPTCHA7.1.1 重点基础知识讲解7.1.2 重点案例&#xff1a;使用Tesseract OCR识别简单CAPTCHA7.1.3 拓展案例 1&#xff1a;使用深度学习模型识别复杂CAPTCHA7.1.4 拓展案例 2&#xff1a;集成第三方 CAPTCHA 解决服务 7.2 IP 轮换与代理的使用7.2.1 重…

荣获双强认证!玻色量子荣登投资界2023Venture50新芽榜数字科技50强

2024年1月16日&#xff0c;由清科创业&#xff08;1945.HK&#xff09;、投资界发起的2023Venture50评选结果成功揭晓&#xff01;此次评选包含风云榜与新芽榜TOP50&#xff0c;以及五大行业榜单。玻色量子作为量子计算领军企业&#xff0c;荣登新芽榜50强与数字科技50强双强榜…

如何将pdf转换成ppt?掌握这个方法就简单多了

有时候&#xff0c;PDF文件的布局和设计可能需要进行微调或重新排版&#xff0c;以适应PPT的特定格式和风格。那么怎么pdf怎么转ppt呢&#xff1f;为了更方便地对布局、字体、图像和其他元素进行编辑和调整&#xff0c;以符合PPT的需求&#xff0c;我们可以直接通过pdf在线转pp…

zabbix server/agent源码编译成rpm包(通用版-小白教程)

前言 工作环境需要用到很多信创的操作系统&#xff0c;zabbix agent2的官方没有现成的包可用&#xff0c;网上巴拉了一下找到zabbix agent2通用版编译成rpm包的方法 思路&#xff1a;假如当你有一批ky10_x86的机器需要配套的zabbix agent的rpm包&#xff0c;那就找一台ky10_x…

【Linux】linux自动化构建工具make/makefile

linux自动化构建工具make/makefile 一&#xff0c;makefile是什么二&#xff0c;如何写makefile三&#xff0c;文件的三个时间属性四&#xff0c;makefile的推导 一&#xff0c;makefile是什么 对于make和makefile&#xff0c;简单来说&#xff0c;make是一个命令&#xff0c;用…

全网第一篇把Nacos配置中心服务端讲明白的

入口 getServerConfig对应&#xff1a;ConfigQueryRequestHandler&#xfffd;getBatchServiceConfig对应&#xff1a;ConfigChangeBatchListenResponse&#xfffd;admin对应&#xff1a;ConfigController 我们重点就要2个&#xff0c;一个是服务端如何完成客户端获取配置请…