HTTP,TCP的长连接和短连接以及socket( 三 )


TCP的keep alive是检查当前TCP连接是否活着;HTTP的Keep-alive是要让一个TCP连接活久点 。它们是不同层次的概念 。
TCP keep alive的表现:
当一个连接“一段时间”没有数据通讯时 , 一方会发出一个心跳包(Keep Alive包) , 如果对方有回包则表明当前连接有效 , 继续监控 。
这个“一段时间”可以设置 。
WinHttp库的设置:

WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL
Sets the interval, in milliseconds, to send a keep-alive packet over the connection. The default interval is 30000 (30 seconds). The minimum interval is 15000 (15 seconds). Using WinHttpSetOption to set a value lower than 15000 will return with ERROR_INVALID_PARAMETER.
libcurl的设置:
http://curl.haxx.se/libcurl/c/curl_easy_setopt.html
CURLOPT_TCP_KEEPALIVE
Pass a long. If set to 1, TCP keepalive probes will be sent. The delay and frequency of these probes can be controlled by the CURLOPT_TCP_KEEPIDLE and CURLOPT_TCP_KEEPINTVL options, provided the operating system supports them. Set to 0 (default behavior) to disable keepalive probes (Added in 7.25.0).
CURLOPT_TCP_KEEPIDLE
Pass a long. Sets the delay, in seconds, that the operating system will wait while the connection is idle before sending keepalive probes. Not all operating systems support this option. (Added in 7.25.0)
CURLOPT_TCP_KEEPINTVL
Pass a long. Sets the interval, in seconds, that the operating system will wait between sending keepalive probes. Not all operating systems support this option. (Added in 7.25.0)
CURLOPT_TCP_KEEPIDLE是空闲多久发送一个心跳包 , CURLOPT_TCP_KEEPINTVL是心跳包间隔多久发一个 。
打开网页抓包 , 发送心跳包和关闭连接如下:
HTTP,TCP的长连接和短连接以及socket

文章插图
 
从上图可以看到 , 大概过了44秒 , 客户端发出了心跳包 , 服务器及时回应 , 本TCP连接继续保持 。到了空闲60秒的时候 , 服务器主动发起FIN包 , 断开连接 。
HTTP,TCP的长连接和短连接以及socket

文章插图
 
Socket是什么
Socket是应用层与TCP/IP协议族通信的中间软件抽象层 , 它是一组接口 。在设计模式中 , Socket其实就是一个门面模式 , 它把复杂的TCP/IP协议族隐藏在Socket接口后面 , 对用户来说 , 一组简单的接口就是全部 , 让Socket去组织数据 , 以符合指定的协议 。
HTTP,TCP的长连接和短连接以及socket

文章插图
 
通信过程:
HTTP,TCP的长连接和短连接以及socket

文章插图
 
主机 A 的应用程序要能和主机 B 的应用程序通信 , 必须通过 Socket 建立连接 , 而建立 Socket 连接必须需要底层 TCP/IP 协议来建立 TCP 连接 。建立 TCP 连接需要底层 IP 协议来寻址网络中的主机 。我们知道网络层使用的 IP 协议可以帮助我们根据 IP 地址来找到目标主机 , 但是一台主机上可能运行着多个应用程序 , 如何才能与指定的应用程序通信就要通过 TCP 或 UPD 的地址也就是端口号来指定 。这样就可以通过一个 Socket 实例唯一代表一个主机上的一个应用程序的通信链路了 。
建立通信链路
当客户端要与服务端通信 , 客户端首先要创建一个 Socket 实例 , 操作系统将为这个 Socket 实例分配一个没有被使用的本地端口号 , 并创建一个包含本地和远程地址和端口号的套接字数据结构 , 这个数据结构将一直保存在系统中直到这个连接关闭 。在创建 Socket 实例的构造函数正确返回之前 , 将要进行 TCP 的三次握手协议 , TCP 握手协议完成后 , Socket 实例对象将创建完成 , 否则将抛出 IOException 错误 。
与之对应的服务端将创建一个 ServerSocket 实例 , ServerSocket 创建比较简单只要指定的端口号没有被占用 , 一般实例创建都会成功 , 同时操作系统也会为 ServerSocket 实例创建一个底层数据结构 , 这个数据结构中包含指定监听的端口号和包含监听地址的通配符 , 通常情况下都是“*”即监听所有地址 。之后当调用 accept() 方法时 , 将进入阻塞状态 , 等待客户端的请求 。当一个新的请求到来时 , 将为这个连接创建一个新的套接字数据结构 , 该套接字数据的信息包含的地址和端口信息正是请求源地址和端口 。这个新创建的数据结构将会关联到 ServerSocket 实例的一个未完成的连接数据结构列表中 , 注意这时服务端与之对应的 Socket 实例并没有完成创建 , 而要等到与客户端的三次握手完成后 , 这个服务端的 Socket 实例才会返回 , 并将这个 Socket 实例对应的数据结构从未完成列表中移到已完成列表中 。所以 ServerSocket 所关联的列表中每个数据结构 , 都代表与一个客户端的建立的 TCP 连接 。


推荐阅读