JAVA Socket超时浅析

深入剖析阻塞式socket的timeout 一个tcp连接建立后,如果一端的物理机突然宕机,另外一端是完全不知情的,它会像往常一样继续发送相关报文,直到超时时间到了才返回。而如果只是进程宕掉,在进程退出的时候,操作会负责回收这个进程所属的所有tcp连接,在这时会向这些tcp连接的对端发送FIN报文,表示要关闭连接了,这时候对端是可以知道连接已经关闭的。在有机器宕机的情况下,如果连接超时时间设置的比较长,而我们客户端的线程池又比较小,就很可能大多数的线程都在等待建立连接,过了较长时间才发现连接不上,影响应用的整体吞吐量。但是可以大致认为是一致的。 阅读详情

JAVA Socket超时浅析

  套接字或插座(socket)是一种软件形式的抽象,用于表达两台机器间一个连接的“终端”。针对一个特定的连接,每台机器上都有一个“套接字”,可以想象它们之间有一条虚拟的“线缆”。JAVA有两个基于数据流的套接字类:ServerSocket,服务器用它“侦听”进入的连接;Socket,客户端用它初始一次连接。侦听套接字只能接收新的连接请求,不能接收实际的数据包。

  套接字是基于TCP/IP实现的,它是用来提供一个访问TCP的服务接口,或者说套接字socket是TCP的应用编程接口API,通过它应用层就可以访问TCP提供的服务。

在JAVA中,我们用ServerSocket、Socket类创建一个套接字连接,从套接字得到的结果是一个InputStream以及OutputStream对象,以便将连接作为一个IO流对象对待。通过IO流可以从流中读取数据或者写数据到流中,读写IO流会有异常IOException产生。

  套接字底层是基于TCP的,所以socket的超时和TCP超时是相同的。下面先讨论套接字读写缓冲区,接着讨论连接建立超时、读写超时以及JAVA套接字编程的嵌套异常捕获和一个超时例子程序的抓包示例。

1 socket读写缓冲区

  一旦创建了一个套接字实例,操作系统就会为其分配缓冲区以存放接收和要发送的数据。

 

 

  JAVA可以设置读写缓冲区的大小-setReceiveBufferSize(int size), setSendBufferSize(int size)。

  向输出流写数据并不意味着数据实际上已经被发送,它们只是被复制到了发送缓冲区队列SendQ,就是在Socket的OutputStream上调用flush()方法,也不能保证数据能够立即发送到网络。真正的数据发送是由操作系统的TCP协议栈模块从缓冲区中取数据发送到网络来完成的。

  当有数据从网络来到时,TCP协议栈模块接收数据并放入接收缓冲区队列RecvQ,输入流InputStream通过read方法从RecvQ中取出数据。

2 socket连接建立超时

  socket连接建立是基于TCP的连接建立过程。TCP的连接需要通过3次握手报文来完成,开始建立TCP连接时需要发送同步SYN报文,然后等待确认报文SYN+ACK,最后再发送确认报文ACK。TCP连接的关闭通过4次挥手来完成,主动关闭TCP连接的一方发送FIN报文,等待对方的确认报文;被动关闭的一方也发送FIN报文,然等待确认报文。


  正在等待TCP连接请求的一端有一个固定长度的连接队列,该队列中的连接已经被TCP接受(即三次握手已经完成),但还没有被应用层所接受。TCP接受一个连接是将其放入这个连接队列,而应用层接受连接是将其从该队列中移出。应用层可以通过设置backlog变量来指明该连接队列的最大长度,即已被TCP接受而等待应用层接受的最大连接数。

  当一个连接请求SYN到达时,TCP确定是否接受这个连接。如果队列中还有空间,TCP模块将对SYN进行确认并完成连接的建立。但应用层只有在三次握手中的第三个报文收到后才会知道这个新连接。如果队列没有空间,TCP将不理会收到的SYN。

  如果应用层不能及时接受已被TCP接受的连接,这些连接可能占满整个连接队列,新的连接请求可能不被响应而会超时。如果一个连接请求SYN发送后,一段时间后没有收到确认SYN+ACK,TCP会重传这个连接请求SYN两次,每次重传的时间间隔加倍,在规定的时间内仍没有收到SYN+ACK,TCP将放弃这个连接请求,连接建立就超时了。

  JAVA Socket连接建立超时和TCP是相同的,如果TCP建立连接时三次握手超时,那么导致Socket连接建立也就超时了。可以设置Socket连接建立的超时时间-

connect(SocketAddress endpoint, int timeout)

如果在timeout内,连接没有建立成功,在TimeoutException异常被抛出。如果timeout的值小于三次握手的时间,那么Socket连接永远也不会建立。

  不同的应用层有不同的连接建立过程,Socket的连接建立和TCP一样-仅仅需要三次握手就完成连接,但有些应用程序需要交互很多信息后才能成功建立连接,比如Telnet协议,在TCP三次握手完成后,需要进行选项协商之后,Telnet连接才建立完成。

3 socket读超时

  如果输入缓冲队列RecvQ中没有数据,read操作会一直阻塞而挂起线程,直到有新的数据到来或者有异常产生。调用setSoTimeout(int timeout)可以设置超时时间,如果到了超时时间仍没有数据,read会抛出一个SocketTimeoutException,程序需要捕获这个异常,但是当前的socket连接仍然是有效的。

  如果对方进程崩溃、对方机器突然重启、网络断开,本端的read会一直阻塞下去,这时设置超时时间是非常重要的,否则调用read的线程会一直挂起。

  TCP模块把接收到的数据放入RecvQ中,直到应用层调用输入流的read方法来读取。如果RecvQ队列被填满了,这时TCP会根据滑动窗口机制通知对方不要继续发送数据,本端停止接收从对端发送来的数据,直到接收者应用程序调用输入流的read方法后腾出了空间。

4 socket写超时

  socket的写超时是基于TCP的超时重传。超时重传是TCP保证数据可靠性传输的一个重要机制,其原理是在发送一个数据报文后就开启一个计时器,在一定时间内如果没有得到发送报文的确认ACK,那么就重新发送报文。如果重新发送多次之后,仍没有确认报文,就发送一个复位报文RST,然后关闭TCP连接。首次数据报文发送与复位报文传输之间的时间差大约为9分钟,也就是说如果9分钟内没有得到确认报文,就关闭连接。但是这个值是根据不同的TCP协议栈实现而不同。

  如果发送端调用write持续地写出数据,直到SendQ队列被填满。如果在SendQ队列已满时调用write方法,则write将被阻塞,直到SendQ有新的空闲空间为止,也就是说直到一些字节传输到了接收者套接字的RecvQ中。如果此时RecvQ队列也已经被填满,所有操作都将停止,直到接收端调用read方法将一些字节传输到应用程序。

  当Socket的write发送数据时,如果网线断开、对端进程崩溃或者对端机器重启动,TCP模块会重传数据,最后超时而关闭连接。下次如再调用write会导致一个异常而退出。

  Socket写超时是基于TCP协议栈的超时重传机制,一般不需要设置write的超时时间,也没有提供这种方法。

5 双重嵌套异常捕获

   如果ServerSocket、Socket构造失败,只需要仅仅捕获这个构造失败异常而不需要调用套接字的close方法来释放资源(必须保证构造失败后不会留下任何需要清除的资源),因为这时套接字内部资源没有被成功分配。如果构造成功,必须进入一个try finally语句块里调用close释放套接字。请参照下面例子程序。


 

 

  执行上面的程序,在程序运行一会儿之后,断开client和server之间的网络连接,在机器上输出如下:

 

Server上的输出:

Echoing:client sent -----hello0

Echoing:client sent -----hello1

Echoing:client sent -----hello2

Echoing:client sent -----hello3

Echoing:client sent -----hello4

Echoing:client sent -----hello5

Echoing:client sent -----hello6

 

---->> 断开了网络连接之后没有数据输出

 

Client上的输出:

socket default timeout = 0

socket = Socket[addr=/10.15.9.99,port=8088,localport=4691]

begin to read

client sent --- hello *** 0

client sent --- hello *** 1

client sent --- hello *** 2

client sent --- hello *** 3

client sent --- hello *** 4

client sent --- hello *** 5

client sent --- hello *** 6

client sent --- hello *** 7

client sent --- hello *** 8  

client sent --- hello *** 9

client sent --- hello *** 10

 

 ---->> 断开网络连接后客户端进程挂起

 

java.net.SocketException : Connection reset by peer: socket write error

    at java.net.SocketOutputStream.socketWrite0( Native Method )

    at java.net.SocketOutputStream.socketWrite( SocketOutputStream.java:92 )

    at java.net.SocketOutputStream.write( SocketOutputStream.java:136 )

    at sun.nio.cs.StreamEncoder.writeBytes( StreamEncoder.java:202 )

    at sun.nio.cs.StreamEncoder.implFlushBuffer( StreamEncoder.java:272 )

    at sun.nio.cs.StreamEncoder.implFlush( StreamEncoder.java:276 )

    at sun.nio.cs.StreamEncoder.flush( StreamEncoder.java:122 )

    at java.io.OutputStreamWriter.flush( OutputStreamWriter.java:212 )

    at java.io.BufferedWriter.flush( BufferedWriter.java:236 )

    at com.xtera.view.SocketClientTest.main( SocketClientTest.java:99 )

 

  当hello6被发送到server端后,网络连接被断开,这时server端不能接收任何数据而挂起。client端仍然继续发送数据,实际上hello7、hello8、hello9、hello10都被复制到SendQ队列中,write方法立即返回。当client的SendQ队列被填满之后,write方法就被阻塞。TCP模块在发送报文hello7之后,没有收到确认而超时重传,再重传几次之后关闭了TCP连接,同时导致被阻塞的write方法异常返回。

  通过抓包工具,我们可以看到超时重传的报文。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


客户端网络socket判定超时(TCP) 网络socket是整个传输层的基础,几乎所有的应用层协议都要经过该层来传输。下面以基于TCP的客户端在阻塞与非阻塞两个模式下的超时判断。一、阻塞socket采用setsockopt。SO_SNDTIMEO:限制send超时。SO_RCVTIMEO:限制recv超时对于connect的超时控制,还需要首先将socket转为非阻塞模型,处理完毕后(见下面二),再转换为阻塞socket,进行发送与接收的... 阅读详情

相关推荐

jvm源码分析之socketWrite

客户端socket使用示例如下: 1.创建Socket对象,指定服务端的地址和端口号 2.建立连接后,通过输出输入流进行读写操作 3.通过输出输入流获取服务器返回信息 4.关闭相关资源 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io...

lzf的博客 1113

Java Socket Timeout总结

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34146986的博客 1163

STM32实战指南:TFTLCD液晶屏驱动与ILI9341应用解析

本文详细解析了STM32驱动TFTLCD液晶屏的实战技巧,重点介绍了ILI9341控制器的硬件连接、寄存器操作及性能优化方法。通过8080并行接口时序分析、GRAM操作优化和DMA传输应用,帮助开发者高效实现液晶屏驱动,适用于工业控制、智能家居等场景。

weixin_26873711的博客 232

2023-03-10 java socket 判断服务端已经断开连接或者被其他用户连接的方法,用sendUrgentData(0xFF)发心跳包和ping ip两者结合

【代码】2023-03-10 java socket 判断服务端已经断开连接或者被其他用户连接的方法,用sendUrgentData(0xFF)发心跳包和ping ip两者结合。

海月汐辰 1310

PTPX功耗分析实战——从脚本配置到报告解读

本文详细介绍了PTPX功耗分析的全流程,从脚本配置到报告解读,帮助工程师快速掌握芯片设计中的功耗估算技术。文章涵盖了环境搭建、波形文件处理、功耗报告解析等关键环节,并提供了实战经验和优化建议,特别适合需要提升PTPX功耗分析效率的开发者。

weixin_29248313的博客 279

Pure Persuit算法基础

Pure Persuit算法本身的原理不难理解,它主要基于几何原理进行的设备控制,本身不考虑太多的运动学约束。同时机器人的路径跟踪效果应该会比较依赖于预瞄点。对于曲线部分而言,如果曲率很小而预瞄点很远的话,对于曲线的跟随性应该会很差。对于直线而言,如果设备在开始时与轨迹有横向偏差,则在运动过程中机器人会逐渐收敛到曲线,但是收敛速度取决于预瞄点距离。

YiYeZhiNian的博客 1522

Java Socket超时浅析

套接字或插座(socket)是一种软件形式的抽象,用于表达两台机器间一个连接的“终端”。针对一个特定的连接,每台机器上都有一个“套接字”,可以想象它们之间有一条虚拟的“线缆”。JAVA 有两个基于数据流的套接字类:ServerSocket,服务器用它“侦听”进入的连接;Socket,客户端用它初始一次连接。侦听套接字只能接收新的连接请求,不能接收实际的数据包。     套接字是基于TCP/IP实

zj的博客 5341

机械臂速成小指南(七):从旋转矩阵到齐次变换——机械臂位姿的数学表达

本文详细介绍了机械臂位姿描述的数学基础,包括旋转矩阵、欧拉角和齐次变换等核心概念。通过解析旋转矩阵的几何意义和合成方法,以及欧拉角的直观描述,帮助读者理解机械臂位姿的数学表达。文章还探讨了齐次变换在工程实践中的应用,并提供了数值稳定性、坐标系约定和计算效率等实用建议。

cuda7parallel的博客 835

java socket 超时_Java Socket超时浅析

套接字或插座(socket)是一种软件形式的抽象,用于表达两台机器间一个连接的“终端”。针对一个特定的连接,每台机器上都有一个“套接字”,可以想象它们之间有一条虚拟的“线缆”。JAVA 有两个基于数据流的套接字类:ServerSocket,服务器用它“侦听”进入的连接;Socket,客户端用它初始一次连接。侦听套接字只能接收新的连接请求,不能接收实际的数据包。套接字是基于TCP/IP实现的,它是用...

weixin_39681058的博客 257

【人工智能之深度学习】15. 工业时序预测实战:LSTM与TCN融合的装备故障预警系统设计与实现

摘要:工业装备故障预警是智能制造领域的核心技术之一,其通过分析传感器时序数据实现故障提前预测,可显著降低运维成本并提升设备可靠性。本文针对工业时序数据多源异构、非平稳性、噪声干扰及样本不平衡等挑战,提出一种LSTM与TCN融合的故障预警架构——利用TCN捕捉局部时序特征,结合注意力增强LSTM建模长期依赖关系,通过门控机制实现特征自适应融合。以3MW风电齿轮箱为研究对象,设计包含数据预处理、特征工程、模型训练及部署的完整流程,实验结果表明,该融合模型准确率达94.6%,故障预测提前量较单一模型提升30%以上

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 1441

Python爬虫实战:基于最新技术栈的晋江文学城小说爬取

本文将详细介绍如何使用Python最新技术栈构建一个高效的晋江文学城小说爬虫。我们将从爬虫基础知识讲起,逐步深入到反爬机制应对、分布式爬虫设计以及数据存储优化等高级话题。文章包含完整的代码实现,使用aiohttp+asyncio实现异步爬取,Playwright处理动态渲染,并结合Redis实现分布式任务队列。本文旨在为读者提供一个全面的现代Python爬虫开发指南。网络爬虫(Web Crawler)是一种自动抓取互联网信息的程序,广泛应用于搜索引擎、数据分析和内容聚合等领域。

2201_76125261的博客 870

java socket发送超时_JAVA Socket超时浅析

JAVA Socket超时浅析套接字或插座(socket)是一种软件形式的抽象,用于表达两台机器间一个连接的“终端”。针对一个特定的连接,每台机器上都有一个“套接字”,可以想象它们之间有一条虚拟的“线缆”。Java有两个基于数据流的套接字类:ServerSocket,服务器用它“侦听”进入的连接;Socket,客户端用它初始一次连接。侦听套接字只能接收新的连接请求,不能接收实际的数据包。套接字是基...

weixin_35075740的博客 552

LDRA Testbed(TBrun)软件单元测试_操作指南

通过前面的几篇文章,使用Testbed进行软件静态分析的内容已经基本讲解完毕。从这篇文章开始,将继续讲解如何使用TBrun进行软件单元测试、软件集成测试。

文章主要涉及嵌入式软件开发、测试、项目管理等,欢迎交流,共同进步。 7766

java socket设置连接超时_JAVA Socket超时浅析

JAVA Socket超时浅析套接字或插座(socket)是一种软件形式的抽象,用于表达两台机器间一个连接的“终端”。针对一个特定的连接,每台机器上都有一个“套接字”,可以想象它们之间有一条虚拟的“线缆”。JAVA有两个基于数据流的套接字类:ServerSocket,服务器用它“侦听”进入的连接;Socket,客户端用它初始一次连接。侦听套接字只能接收新的连接请求,不能接收实际的数据包。套接字是基...

weixin_29938067的博客 733

2024年电气工程师最新面试题及答案

1. **基本电气工程原理**:包括电流、电压、电阻、功率等基本概念。2. **欧姆定律**:V = IR,描述电压、电流和电阻之间的关系。42. **风力发电系统组成**:包括风力涡轮机、发电机、控制系统等。44. **智能电网技术**:包括自动化控制、通信技术、数据分析等。10. **减少EMI**:使用屏蔽、滤波、合理布线等方法。40. **光伏系统组成**:包括光伏板、逆变器、控制器等。48. **能量存储技术**:包括电池、超级电容器、飞轮等。

guo162308的博客 6562

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

java socket 超时_JAVA Socket超时浅析(转)

套接字或插座(socket)是一种软件形式的抽象,用于表达两台机器间一个连接的“终端”。针对一个特定的连接,每台机器上都有一个“套接字”,可以想象它们之间有一条虚拟的“线缆”。JAVA有两个基于数据流的套接字类:ServerSocket,服务器用它“侦听”进入的连接;Socket,客户端用它初始一次连接。侦听套接字只能接收新的连接请求,不能接收实际的数据包。套接字是基于TCP/IP实现的,它是用来...

weixin_33330762的博客 493

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

上一篇: JAVA动态绑定的内部实现机制
下一篇: JAVA RMI线程模型及内部实现机制
飞天金刚
博客等级 码龄17年 35粉丝 15原创
评论 9
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值