websocket解析

参考:https://www.cnblogs.com/songwenjie/p/8575579.html
demo:https://blog.csdn.net/WangMapleWang/article/details/87009945

首先抓包看下websocket请求
在这里插入图片描述

Websocket 握手

Request:

GET ws://localhost:8080/imWebSocket/test2 HTTP/1.1
Host: localhost:8080
Upgrade: websocket
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Mobile Safari/537.36
Origin: http://localhost:8080
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: JSESSIONID=DF854DB505EE3452FCBCF6284FF21725
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: jKmwUQ7MtDb456lQIUy3ew==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits

Response:

HTTP/1.1 101
Upgrade: websocket
Connection: upgrade
Sec-WebSocket-Accept: udwnrhEtaHeeHPCxCideCLz3DGM=
Sec-WebSocket-Extensions: permessage-deflate;client_max_window_bits=15
Date: Wed, 16 Jan 2019 02:15:08 GMT

WebSocket的连接都基于HTTP请求,那怎么区分这次请求是HTTP还是WebSocket呢?
Connection: Upgrade 表示要升级协议
Upgrade: websocket 升级到websocket
客户端想把HTTP协议转为WebSocket,通过更新头字段(Upgrade header)向服务器指定传输协议类型。这个就是Websocket的核心,告诉 Apache 、 Nginx 等服务器:注意啦,我发起的是Websocket协议。此时HTTP连接会被基于TCP/IP连接的WebSocket连接所取代。
WebSocket连接默认使用和HTTP(80)或者HTTPS(443)一样的端口,同样,你可以像部署Web服务一样使用其它端口。

Sec-WebSocket-Version: 13:表示websocket的版本。如果服务端不支持该版本,需要返回一个Sec-WebSocket-Versionheader,里面包含服务端支持的版本号。

WebSocket的连接是怎么握手验证的?
客户端请求中的Sec-WebSocket-Key是随机的,服务器端会用这些数据来构造出一个SHA-1的信息摘要。把Sec-WebSocket-Key加上一个魔幻字符串258EAFA5-E914-47DA-95CA-C5AB0DC85B11。使用 SHA-1 加密,之后进行 BASE-64编码,将结果作为 Sec-WebSocket-Accept 头的值,返回给客户端。客户端同样算法校验正确性完成握手。

def ws_accept_key(ws_key):
    """calc the Sec-WebSocket-Accept key by Sec-WebSocket-key
    come from client, the return value used for handshake

    :ws_key: Sec-WebSocket-Key come from client
    :returns: Sec-WebSocket-Accept

    """
    import hashlib
    import base64
    try:
        magic = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
        sha1 = hashlib.sha1()
        sha1.update(ws_key + magic)
        return base64.b64encode(sha1.digest())
    except Exception as e:
        return None

print 'udwnrhEtaHeeHPCxCideCLz3DGM='.__eq__(ws_accept_key('jKmwUQ7MtDb456lQIUy3ew=='))

wireshark抓包分析

几个概念:
SYN:同步比特,建立连接。
ACK:确认比特,置1表示这是一个确认的TCP包,0则不是。
PSH:推送比特,当发送端PSH=1时,接收端应尽快交付给应用进程。
Sequence number: 序列号
Acknowledgment number:确认号

tcp的三次握手:
第一次握手:

传输层Transmission Control Protocol(TCP),SYN置为1,客户端向服务端发送连接请求包。

在这里插入图片描述

第二次握手:

服务端接收到客户端的syn=1的连接请求,向客户端发送syn=1,确认号ack+1的报文

在这里插入图片描述

第三次握手

客户端验证服务端返回的报文,确认序列号(seq+1),标志位ack=1。确认成功再次想服务端发送ack=1的确认包表示链接成功,可以发送数据了

在这里插入图片描述

在这里插入图片描述

TCP Window

一般指的是TCP Receive Window,在TCP连接两端都有的缓冲区用于暂时保存到来的数据。在这个缓冲区中的数据会被发送到应用程序中, 为新到来的数据腾出空间. 如果这个缓冲满了, 那么数据的接收方会警告发送方在缓冲去清空之前已经不能在收取更多的数据了,

设备会在TCP Header信息中通知对方当前它的TCPWindows的大小.
在上图的Window size value 是12743, 这个包的发送方告诉连接的另一端: 他的TCP Receive Buffer是12743个字节. 标准TCP Window Size的最大值是65535.

TCP连接的任意一段都有自己的TCP Receive Window. 所以在任何时候, 这两个window的大小都可能会不一样. 比如说一个Web Server通常发送数据给用户, 而不是从用户那里获得数据. 基于这个原因, Web Server不需要像普通用户需要那么大的TCP Window. 所以Web Server会告知它的receive window是8192字节, 而客户端的window却是65535字节.

如何影响性能?

在一个文件传输的时候, 数据从一台机器流向另一台. 数据接收方需要阻止它的TCP Window降为0, 意味着window填满了。如果一个TCP Window变为0了, 或者接近0了, 这就会警告数据发送方没有更多空间来接受更多数据了。文件传输会停止, 直到收到一个update说buffer已经清空了。

TCP长连消息的顺序

在一次长连接中,服务器怎么知道消息的顺序呢?
这就涉及到tcp的序列号(Sequence Number)和确认号(Acknowledgment Number)

每一端的序列号都是从0开始,三次握手中是无数据包传输的但是接收的包中包含SYN或FIN标志位,故序列号也在原有值上+1

64559 8080 sever TCP三次握手 数据包是无数据的 syn=1 建立连接标志位,seq=0,ack=0 syn=1 建立连接标志位,seq=0,ack+1响应接收到了客户端的syn ack+1响应接收到了服务端的syn,服务端的ack=1确认收到客户端的syn,故seq+1=1 http协议 seq=1,ack=1(到上个包为止ack不变、无包数据,故seq ack不变化),len=579 seq=1,ack=580=579+1,len=0 从客户端接收了5 79字节的数据, 服务端的确认号由 1增长至580。 seq=1(服务端在该包之前返回的包中都不带有效数据),ack=580,len=219 seq=580,ack=220,len=0 由于上个数据包的发送,TCP客户端的确认 序列号增长至580.从服务端接收了219 字节的数据,客户端的确认号由1增长至22 0。 websocket协议 seq=580,ack=220,len=86 seq=220,ack=666,len=0 由于上个服务的数据包219的发送, TCP服务端的确认序列号增长至22 0。从客户端接收了86字节的数据, 客户端的确认号由580增长至666。 TCP保活报文总是成对出现,包括T CP保活探测报文和TCP保活探测确 认报文。TCP保活探测报文是将之前 TCP报文的确认序列号减1,TCP 保活探测确认报文就是对保活探测报文 的确认 tcp keep-alive seq=665,ack=220 tcp keep-alive seq=220,ack=666 tcp keep-alive seq=665,ack=220 tcp keep-alive seq=220,ack=666 64559 8080 sever
keep-alive

keep-alive 的原理就是 TCP 内嵌的一个心跳包。

以服务器端为例,如果当前 server 端检测到超过一定时间(默认是 7,200,000 milliseconds ,也就是 2 个小时)没有数据传输,那么会 向client 端发送一个 keep-alive packet (该 keep-alive packet 就是 ACK 和当前 TCP 序列号减一的组合),此时 client 端应该为以下三种情况之一:

  1. client 端仍然存在,网络连接状况良好。此时 client 端会返回一个 ACK 。 server 端接收到 ACK 后重置计时器,在 2 小时后再发送探测。如果 2 小时内连接上有数据传输,那么在该时间基础上向后推延 2 个小时。

  2. 客户端异常关闭,或是网络断开。在这两种情况下, client 端都不会响应。服务器没有收到对其发出探测的响应,并且在一定时间(系统默认为
    1000 ms )后重复发送 keep-alive packet ,并且重复发送一定次数( 2000 XP 2003 系统默认为 5 次 , Vista 后的系统默认为 10 次)。

  3. 客户端曾经崩溃,但已经重启。这种情况下,服务器将会收到对其存活探测的响应,但该响应是一个复位,从而引起服务器对连接的终止。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值