WebSocket小叙

概述

刚看到WeSocket的时候,我以为是HTTP相关,但是在前两天搭了一个简单的Client之后, 我发现这不就是TCP长连接么? 建立连接->通信->断开连接. 直到今天, 我在调试的时候, 发现发出了HTTP请求, 我想, 事情可能不是我想的那样.

先来简单描述一下当时的情况

我用Python代码简单打了一个WebSocket 客户端, 想着试一试, 代码很简单, 就是这:

import websocket
import threading
import time

class Status:
    INIT = 'init'
    OPENED = 'opened'
    CLOSED = 'closed'

class WSTest:
    def __init__(self):
        self.thread = None
        self.ping_thread = None
        self.ws = None
        self.status = Status.INIT

    def send_message(self, message) -> bool:
        if self.status != Status.OPENED:
            return False
        self.ws.send(message)
        return True
    def close(self):
        self.ws.close()
        # 等待关闭
        for i in range(200):
            time.sleep(0.02)
            if self.status == Status.CLOSED:
                break
        if self.status != Status.CLOSED:
            return
        if self.ping_thread and self.ping_thread.is_alive():
            self.ping_thread.join()
    def run(self):
        def on_message(ws, message):
            print(message)
        def on_error(ws, error):
            print(error)
        def on_close(ws):
            print('关闭连接')
            self.status = Status.CLOSED
        def on_open(ws):
            self.status = Status.OPENED
        self.ws = websocket.WebSocketApp("ws://echo.websocket.org",
                                         on_open=on_open,
                                         on_message=on_message,
                                         on_close=on_close,
                                         on_error=on_error)
        self.ping_thread = threading.Thread(target=self.ws.run_forever, args=(None, None, 2, 5))
        self.ping_thread.start()

if __name__ == "__main__":
    ws = WSTest()
    ws.run()
    while True:
        s = input()
        if s == 'close':
            break
        ws.send_message(s)
    ws.close()

上面的ws://echo.websocket.org 是一个测试用的域名,你发送什么过去,他就会返回什么. 到这里我简单运行了一下,还可以.本来我想简单搭一个,能调通就得了呗,但是,手贱的我打开了wireshark. 我想看一下它的网络连接. 

wireshark抓包查看

首先,找到域名的IP

找到IP后就可以直接对IP进行过滤,找到接收和发送的数据包.直接过滤所有DNS解析请求,查找指定域名.

然后,针对地址对请求进行过滤

来来来,看到了什么?前面三个TCP请求是三次握手的请求,在三次握手之后的第一个请求是什么,HTTP????

看一下它的请求内容:

看到第一个Upgrade之后,我仿佛懂了.这个字段的含义是要将协议升级.后面跟着的就是websocket了,再看一下服务器的response.(后面那个TCP请求可以跳过,就是服务器告诉你它收到了).

响应内容虽然有不明白的地方,但是大概看来,是同意升级协议的意思了.再然后才是websocket通信内容,以及最后的挥手告别.

也就是说,websocket虽然能够实现双向通信,但是它的连接建立是从HTTP开始,然后升级协议来的??

所以websocket的通信流程是:

  1. 三次握手建立TCP通信
  2. 发起HTTP请求,升级为websokcet协议
  3. 开始websocket通信
  4. 断开连接

如果把中间的websocket去掉,那就完全是HTTP协议了. 没想到websocketHTTP是兄弟俩.

思考

既然WebSocket是基于HTTP协议建立的, 那么他的出现就一定是在HTTP之后, 这就说明它一定是为了解决HTTP的某些问题而出现的. 很显然: HTTP的单向通信限制, 服务器不能主动联系客户端

HTTP协议本身就是基于TCP的, 而TCP本身就是全双工通信的. 这感觉就像是他们借用了一下HTTP, 然后说咱们接下来就都用WebSocket吧.

那么问题来了, 既然要实现这种长连接, 为什么还要借助HTTP之手, 直接TCP建立连接不行么? 查了一下, 发现是为了兼容. 因为WebSocket就是为了解决HTTP协议问题, 也就是说主要运行在之前HTTP的场景中, 而为了兼容现有浏览器的握手规范, 所以借助了HTTP协议来完成握手.

WebSocket协议是: wswss. 其区别与 httphttps 相同. wss 就是在 ws 的通信过程中再套一层TLS/SSL 协议.

那么WebSocket有哪些应用场景呢?

可以这么说, 在原来使用HTTP协议进行轮训的场景, 都可以使用WebSocket替换.

  • 在线聊天
  • 直播
  • 在线多人游戏
  • 等等....

最后, 记一下建立连接的HTTP请求的头信息

request

  • connection: Upgrade 升级协议
  • Upgrade: websocket 指定升级为WebSocket协议
  • Sec-WebSocket-Key: 用于判断客户端是否有权升级协议
  • Sec-WebSocket-Version:指定WebSocket 版本

response

  • Upgrade: websocket 成功升级协议
  • Sec-WebSocket-Accept: 通过Sec-WebSocket-Key计算得来

本文分享自微信公众号 - 烟草的香味(hujing-bc),作者:胡靖哥哥

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-03-14

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • GC算法-标记压缩算法

    还记得标记清除和复制算法的问题么? 堆使用效率低和碎片化问题. 那么有没有能够利用整个堆, 有没有内存碎片化问题的算法呢? 这就是标记压缩算法了.

    烟草的香味
  • UML类图基础说明

    当然, 类图也不一定每一次都长这样, 比如你只分析各个类之间的关系时, 甚至可以只给出类名; 如果是一个接口的话, 可以不给出属性, 只留下类名和方法.

    烟草的香味
  • 贪婪算法回顾

    还记的贪婪算法么? 如果你不记得了, 看了下面这个例子你一定会想起来, 因为这个例子太普遍了, 几乎每个将贪婪算法的地方, 第一个例子都是它, 言归正传.

    烟草的香味
  • SAP Data Intelligence API返回错误消息 - Fordidden cross-site request

    添加HTTP field - X-Requested-With HTTP value - XMLHttpRequest

    Jerry Wang
  • Django基于websocket实现群聊功能

    Django支持http协议和websocket协议,并且可以识别不同协议请求的原因是channels的ProtocolTypeRouter类的下面代码:

    GH
  • Jmeter接口测试-websocket测试

    https://github.com/maciejzaleski/JMeter-WebSocketSampler/wiki/Dependencies

    louiezhou001
  • Python操作高版本Excel文件:颜色、边框、合并单元格

    本文主要颜色Python扩展库openpyxl的一些基本用法,包括创建工作簿、选择活动工作表、写入单元格数据,设置单元格字体颜色、边框样式,合并单元格等等。 f...

    Python小屋屋主
  • CSDN 已下载资源自动批量评论脚本

    用 Python 实现自动批量打分评论指定 CSDN 账号内所有下载过待评论的资源。

    mzlogin
  • OpenGL ES 2.0 (iOS)[03]:熟练图元绘制,玩转二维图形

    文章的大前提是,你得有《OpenGL ES 2.0 (iOS): 一步从一个小三角开始》的基础知识。

    半纸渊
  • Python中相同的值在内存中到底会保存几份

    Python采用基于值的内存管理模式,相同的值在内存中只有一份。这是很多Python教程上都会提到的一句话,但实际情况要复杂的多。什么才是值?什么样的值才会在内...

    Python小屋屋主

扫码关注云+社区

领取腾讯云代金券