http1.1与http1.0最大的区别是什么?
答案是http1.1协议是默认开启keep-alive的,开启后会与服务端保持一定时间的长连接,如图http1.1的请求头:
那什么是keepalive?作用是什么?
keepalive是在TCP中一个可以检测死连接的机制,可以保持tcp长连接不被断开,属于tcp层功能。http1.1协议默认开启keepa-live保持长连接,主要作用是提高对tcp连接的复用率,减少创建连接过程给系统带来的性能损耗。TCP层怎么做到保持长连接的呢?
先看keepalive的用法:有三个参数,开放给应用层使用:
1. sk->keepalive_probes:探测重试次数,超过次数则close连接;2. sk->keepalive_time 探测的心跳间隔,TCP连接在间隔多少秒之后未进行数据传输,则启动探测报文;3. sk->keepalive_intvl 探测间隔,发送探活报文,未收到回复时,重试的时间间隔;
linux系统对这三个参数有默认配置,查看:
[***@*** ~]$ $ cat/proc/sys/net/ipv4/tcp_keepalive_time300[***@*** ~]$ cat /proc/sys/net/ipv4/tcp_keepalive_intvl75[***@*** ~]$ cat /proc/sys/net/ipv4/tcp_keepalive_probes9
应用层使用示例:
- int keepalive = 1; // 开启keepalive属性
- int keepidle = 60; // 如该连接在60秒内没有任何数据往来,则进行探测
- int keepinterval = 5; // 探测时发包的时间间隔为5 秒
- int keepcount = 3; // 探测尝试的次数。如果第1次探测包就收到响应了,则后2次的不再发。并且清零该计数
- setsockopt(rs, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive , sizeof(keepalive ));
- setsockopt(rs, SOL_TCP, TCP_KEEPIDLE, (void*)&keepidle , sizeof(keepidle ));
- setsockopt(rs, SOL_TCP, TCP_KEEPINTVL, (void *)&keepinterval , sizeof(keepinterval ));
- setsockopt(rs, SOL_TCP, TCP_KEEPCNT, (void *)&keepcount , sizeof(keepcount ));
- keepcount: 覆盖 tcpkeepaliveprobes
- keepidle: 覆盖 tcpkeepalivetime
- keepinterval: 覆盖 tcpkeepalive_intvl对于一个经过三次握手已建立好的tcp连接,如果在keepalive_time时间内双方没有任何的数据包传输,则开启keepalive功能,一端将发送keepalive数据心跳包,若没有收到应答,则每隔keepalive_intvl时间间隔再发送该数据包,发送keepalive_probes次,一直没有收到应答,则发送rst包关闭连接,若收到应答,则将计时器清零。
根据抓包继续分析keepalive发送及回复的心跳包内容:先看tcp头的结构为:
typedef struct _TCP_HEADER{
short m_sSourPort; // 源端口号16bit short m_sDestPort; // 目的端口号16bit unsigned int m_uiSequNum; // req字段 序列号32bit unsigned int m_uiAcknowledgeNum; //ack字段 确认号32bit short m_sHeaderLenAndFlag; // 前4位:TCP头长度;中6位:保留;后6位:标志位 short m_sWindowSize; //win字段 窗口大小16bit short m_sCheckSum; // 检验和16bit short m_surgentPointer; // 紧急数据偏移量16bit}__attribute__((packed))TCP_HEADER, *PTCP_HEADER;
看发送的心跳包内容 :
0000 d4 6d 50 f5 02 7f f4 5c 89 cb 35 29 08 00 //mac头 14字节: 45 00 // ip头 20字节 :0010 00 28 10 f4 00 00 40 06 5b dd ac 19 42 76 0a b30020 14 bd e4 4a 1f 7c 32 7e 7a cb 4c bc 55 08 50 10 // tcp头 20字节0030 10 00 3f 00 00 00//分析tcp头部内容e4 4a //源端口号16bit 10进制为:584421f 7c //目的端口号16bit 10进制为 : 806032 7e 7a cb // req字段 序列号32bit 10进制为 : 4c bc 55 08 // ack字段 确认号32bit5 // 前4位:TCP头长度 5*4 =20 字节 没问题0 10 /// 中6位:保留;后6位:标志位 10 代表倒数第5位为1, 标识改tcp包为 ACK 确认包 0030 10 00 3f 00 00 00
继续看回复的心跳包内容 :<