网络请求的超时原因

摘要:
编程语言的SocketAPI主要就是抽象了网卡和内核的逻辑部分,让应用开发人员使用时不必考虑太多细节。一般服务端宕机、网络不可达等原因会造成这样的失败。若是对端机器宕机或者网络断开,接收端的线程仍在阻塞,就会导致连接不能正常关闭。发送超时Socket的写超时是基于TCP的超时重传。Socket写超时是基于TCP协议栈的超时重传机制,一般不需要设置发送超时时间,也没有提供这种方法。

网络的抽象表示

操作系统中,所有网络请求的建立和数据传输,在软件层面是使用socket(一般翻译为套接字)来表示,可以把它理解为搭建在网络请求的客户端和服务端之间的一个管道,socket的建立类比管道的搭建,数据的传输类比管道内水的流动。
套接字是基于TCP/IP实现的,它是TCP的接口在编程语言内的抽象,比如在Java语言中就有对应的ServerSocketSocket类,直接使用编程语言抽象的Socket API即可使用TCP服务。

套接字概述

以Java语言的套接字编程为例,网络中的数据被网卡接收,网卡把接收到的数据放到自己的接收队列(ReceiveQueue)中,用户态执行的代码没有办法直接获取网卡的数据,需要通过调用操作系统函数让内核层的代码获取网卡队列的数据,然后再交由用户编写的代码处理。
同样的,用户编写的代码需要向网络中发送数据时,需要通过调用操作系统函数把数据交由内核,然后由内核代码将数据发送至网卡,网卡把待发送的数据放在发送队列(SendQueue)中,等队列满或者内核主动触发发送的指令,再把队列中的数据发送至网络。

网络请求的超时原因第1张

上述内容中接收队列(ReceiveQueue)和发送队列(SendQueue)称为操作系统的网络缓冲区。编程语言的Socket API主要就是抽象了网卡和内核的逻辑部分,让应用开发人员使用时不必考虑太多细节。例如可以直接通过SocketsetSendBufferSize(int):void控制某个连接的缓冲区大小,也可以直接调用Writerflush():void让网卡把缓冲区的数据发送至网络。

超时

连接超时

使用Socket编程或者HTTP编程,在建立连接的时候,经常会遇到连接超时(connect timeout)。一般服务端宕机、网络不可达等原因会造成这样的失败。在Scoket中,默认connect(SocketAddress):void连接方式,连接失败时会有异常java.net.ConnectException: Connection timed out: connect。使用带有连接超时参数的连接方式connect(SocketAddress, int):void,在超时时间内未连接成功会抛出异常。

等待超时(Socket读超时)

接收队列ReceiveQueue中用来存放从网络中接收的数据,若是ReceiveQueue没有数据,接收端会一直阻塞,直到有新的数据到来或者异常发生。若是对端机器宕机或者网络断开,接收端的线程仍在阻塞,就会导致连接不能正常关闭。
通过setSoTimeout(int):void设置等待时间,若是在指定时间内ReceiveQueue没有数据产生,就会有SocketTimeoutException异常,此时Socket连接仍是有效的,为保证资源的释放,需要在异常发生时关闭连接。

发送超时(Socket写超时)

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

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

当Socket的write():void发送数据时,如果网线断开、对端机器宕机等,TCP模块会重传数据,最后超时而关闭连接。下次如再调用write():void会导致一个异常而退出。

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

而在OKHttp3中提供了基于HTTP的writeTimeout(long, TimeUnit)设置,OKHttp3提供的writeTimeout(long, TimeUnit)并不是设置数据发送到对端的超时时间,而是指在等待发送数据的过程中,可能由于数据一直被加锁导致当前程序无法读取,导致应用层的write()方法阻塞到指定时间而失败。

免责声明:文章转载自《网络请求的超时原因》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Java中File类如何扫描磁盘所有文件包括子目录及子目录文件推荐个开源在线文档,助道友领悟 Django 之“道”下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

WebSocket与消息推送

目录 一、Socket简介 二、WebSocket简介与消息推送 三、WebSocket客户端 四、WebSocket服务器端 五、测试运行 六、小结与消息推送框架 6.1、开源Java消息推送框架 Pushlet 6.2、开源DotNet消息推送框架SignalR B/S结构的软件项目中有时客户端需要实时的获得服务器消息,但默认HTTP协议...

Linux高性能server编程——定时器

版权声明:本文为博主原创文章。未经博主允许不得转载。 https://blog.csdn.net/walkerkalr/article/details/36869913...

Linux网络编程笔记(修订版)

我的网络编程笔记, 因为最近又要做Linux下的网络编程,故重新修订, 其中一些内容参考了文末的链接及文章 1.   基本概念 2.   基本接口 2.1.   打开一个socket 2.2.   将socket绑定定指定的端口—bind 2.3.   侦听socket—listen (服务器端) 2.4.   等待接收请求—accept (服务器端) 2...

网络编程学习小结

几种网络编程方式: ISAPI、CGI、WinInet、Winsock 它们之间的差别: 1) ISAPI主要是开发基于浏览器client与server端程序。效率比CGI方式高,并且也扩展了CGI没有的一些功能。(基于TCP/IP模型中的应用层) 2) CGI主要是开发基于浏览器client与server端程序。(基于TCP/IP模型中的应用层...

WinSock学习笔记

Socket(套接字) ◆先看定义: typedef unsigned int u_int; typedef u_int SOCKET; ◆Socket相当于进行网络通信两端的插座,只要对方的Socket和自己的Socket有通信联接,双方就可以发送和接收数据了。其定义类似于文件句柄的定义。 ◆Socket有五种不同的类型: 1、流式套接字(st...

SOAP、SOCKET协议

一、SOAP( SOAP:Simple Object Access Protocol) 简单对象访问协议,简单对象访问协议(SOAP)是一种轻量的、简单的、基于 XML 的协议,它被设计成在 WEB 上交换结构化的和固化的信息。 SOAP 可以和现存的许多因特网协议和格式结合使用,包括超文本传输协议( HTTP),简单邮件传输协议(SMTP),多用途网际邮件...