zoukankan      html  css  js  c++  java
  • 网络请求的超时原因


    网络的抽象表示

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

    套接字概述

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

    上述内容中接收队列(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()方法阻塞到指定时间而失败。

  • 相关阅读:
    NOIP2010普及组T3 接水问题 ——S.B.S.
    【NOIP提高组2015D2T1】uva 714 copying books【二分答案】——yhx
    【NOIP合并果子】uva 10954 add all【贪心】——yhx
    #include <NOIP2009 Junior> 细胞分裂 ——using namespace wxl;
    #include <NOIP2008 Junior> 双栈排序 ——using namespace wxl;
    NOIP2010普及组 三国游戏 -SilverN
    NOIP2009 提高组T3 机器翻译 解题报告-S.B.S
    NOIP2010提高组乌龟棋 -SilverN
    NOIP2010提高组 机器翻译 -SilverN
    UVa 297 Quadtrees -SilverN
  • 原文地址:https://www.cnblogs.com/weegee/p/13475864.html
Copyright © 2011-2022 走看看