Websocket 学习

一、含义

  WebSocket 是一种在单个TCP连接上进行全双工通讯的协议。

   WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

二、Websocket 产生背景

  很多网站为了实现推送技术,所用的技术都是轮询。

  轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。

  传统的模式的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。

  比较新的技术去做轮询的效果是Comet。

  Comet 是一种用于web的推送技术,能使服务器实时地将更新的信息传送到客户端,而无须客户端发出请求,目前有两种实现方式,长轮询和iframe流。

  长轮询 是在打开一条连接以后保持,等待服务器推送来数据再关闭的方式。

  iframe流 方式是在页面中插入一个隐藏的iframe,利用其src属性在服务器和客户端之间创建一条长链接,服务器向iframe传输数据(通常是HTML,内有负责插入信息的javascript),来实时更新页面。

  Comet技术虽然可以双向通信,但依然需要反复发出请求。

   Comet中,普遍采用的长链接,也会消耗服务器资源。

  Websocket使用和 HTTP 相同的 TCP 端口,可以绕过大多数防火墙的限制。

  默认情况下,Websocket协议使用80端口;运行在TLS之上时,默认使用443端口。

  WebSocket 是独立的、创建在 TCP 上的协议。

  Websocket 通过 HTTP/1.1 协议的101状态码进行握手。

  为了创建Websocket连接,需要通过浏览器发出请求,之后服务器进行回应,这个过程通常称为“握手”(handshaking)。

三、Python编写Socket服务端

1.客户端
客户端:浏览器(必须要有socket包或者类库,一般自带,个别浏览器没有,所以websocket有局限性)
  <script type="text/javascript">
    # 创建连接
    # 发送消息
    # 接收验证消息 下面的一句话做了上面的三件事
    var socket = new WebSocket("ws://127.0.0.1:8002/xxoo"); 

    # 与服务器端连接成功后,自动执行
    socket.onopen = function () {

    };

    # 服务器端向客户端发送数据时,自动执行
    socket.onmessage = function (event) {

    };
  </script>
2.服务端
import socket

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((‘127.0.0.1‘, 8002))
sock.listen(5)
# 获取客户端socket对象
conn, address = sock.accept()
# 获取客户端的【握手】信息
data = conn.recv(1024)
...
...
...
conn.send(‘响应【握手】信息‘)

  请求握手时,浏览器发来的请求信息

GET /chatsocket HTTP/1.1
Host: 127.0.0.1:8002
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
Origin: http://localhost:63342
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: mnwFxiOlctXFN/DeMt1Amg==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits

请求和响应的【握手】信息需要遵循规则:

  • 从请求【握手】信息中提取 Sec-WebSocket-Key
  • 利用magic_string 和 Sec-WebSocket-Key 进行hmac1加密,再进行base64加密
  • 将加密结果响应给客户端

注:magic string为:258EAFA5-E914-47DA-95CA-C5AB0DC85B11

    其中 Sec-WebSocket-Key: mnwFxiOlctXFN/DeMt1Amg== 是浏览器给服务端的一个随机字符串(mnwFxiOlctXFN/DeMt1Amg==),服务端需要给这个随机字符串进行加密,然后在给浏览器send数据的时候带上这个加密后的随机字符串,如果浏览器可以解密,那么就是说服务端支持websocket,进而进行建立连接通信。

  提取Sec-WebSocket-Key值并加密:

import socket
import base64
import hashlib

def get_headers(data):
    """
    将请求头格式化成字典
    :param data:
    :return:
    """
    header_dict = {}
    data = str(data, encoding=‘utf-8‘)

    for i in data.split(‘\r\n‘):
        print(i)
    header, body = data.split(‘\r\n\r\n‘, 1)
    header_list = header.split(‘\r\n‘)
    for i in range(0, len(header_list)):
        if i == 0:
            if len(header_list[i].split(‘ ‘)) == 3:
                header_dict[‘method‘], header_dict[‘url‘], header_dict[‘protocol‘] = header_list[i].split(‘ ‘)
        else:
            k, v = header_list[i].split(‘:‘, 1)
            header_dict[k] = v.strip()
    return header_dict

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((‘127.0.0.1‘, 8002))
sock.listen(5)

conn, address = sock.accept()
data = conn.recv(1024)
headers = get_headers(data) # 提取请求头信息
# 对请求头中的sec-websocket-key进行加密
response_tpl = "HTTP/1.1 101 Switching Protocols\r\n"       "Upgrade:websocket\r\n"       "Connection: Upgrade\r\n"       "Sec-WebSocket-Accept: %s\r\n"       "WebSocket-Location: ws://%s%s\r\n\r\n"
magic_string = ‘258EAFA5-E914-47DA-95CA-C5AB0DC85B11‘
value = headers[‘Sec-WebSocket-Key‘] + magic_string
ac = base64.b64encode(hashlib.sha1(value.encode(‘utf-8‘)).digest())
response_str = response_tpl % (ac.decode(‘utf-8‘), headers[‘Host‘], headers[‘url‘])
# 响应【握手】信息
conn.send(bytes(response_str, encoding=‘utf-8‘))
...
...
...

  此外还有服务端需要实现封包解包的功能,而客户端浏览器的JS已经帮我们实现了封包解包了。

  封包解包详见:武沛齐

  

时间: 2024-10-10 21:32:49

Websocket 学习的相关文章

WebSocket 学习(三)--用nodejs搭建服务器

前面已经学习了WebSocket API,包括事件.方法和属性.详情:WebSocket(二)--API  WebSocket是基于事件驱动,支持全双工通信.下面通过三个简单例子体验一下. 简单开始 1.安装node.https://nodejs.org/en/ 2.安装ws模块 ws:是nodejs的一个WebSocket库,可以用来创建服务. https://github.com/websockets/ws 3.server.js 在项目里面新建一个server.js,创建服务,指定8181

python websocket学习使用

前言 今天看了一些资料,记录一下心得. websocket是html5引入的一个新特性,传统的web应用是通过http协议来提供支持,如果要实时同步传输数据,需要轮询,效率低下 websocket是类似socket通信,web端连接服务器后,握手成功,一直保持连接,可以理解为长连接,这时服务器就可以主动给客户端发送数据,实现数据的自动更新. 使用websocket需要注意浏览器和当前的版本,不同的浏览器提供的支持不一样,因此设计服务器的时候,需要考虑. 进一步简述 websocket是一个浏览器

【Todo】Websocket学习

首先是在Tomcat里面看到Websocket的演示.很有意思. http://localhost:8080/examples/websocket/index.xhtml 里面有: Echo example Chat example Multiplayer snake example Multiplayer drawboard example 都实现的非常有意思.上网一查,原来websocket是H5里面很有意思的技术.

webSocket学习

### 一.首先查了一下socket和websocket的区别 要了解,这两者的区别,最好的方法就是了解二者本身,那么区别也就不言而喻了. 原文出处: TheAlchemist 当我们探讨两件事物的区别和联系时,我们想探讨些什么? 前段时间写了两篇介绍 HTTP 和 WebSocket 的文章,回复中有人说希望了解下WebSocket和Socket的区别.这个问题之前也有想过,自己对此是有大概的答案,可是并不太确定,于是去搜集了些资料(其实就是各种Google),看了很多以前的文档,觉得有些故事

WebSocket学习笔记IE,IOS,Android等设备的兼容性问

一.背景 公司最近准备将一套产品放到Andriod和IOS上面去,为了统一应用的开发方式,决定用各平台APP嵌套一个HTML5浏览器来实现,其中数据通信,准备使用WebSocket的方式.于是,我开始在各大浏览器上测试. 二.协议分析 2.1 WebSocket的请求包 首先把原来做Socket通信的程序拿出来,跟踪下浏览器在WebSocket应用请求服务端的时候发的数据包的内容: IE11: GET /chat HTTP/1.1 Origin: http://localhost Sec-Web

WebSocket学习记录

参考资料: Java后端WebSocket的Tomcat实现 java WebSocket的实现以及Spring WebSocket 基于Java的WebSocket推送 基于GoEasy实现Java web实时数据推送 使用GoEasy实现web实时推送

WebSocket学习笔记

WebSocket的优点: 1. 节约带宽. 不停地轮询服务端数据这种方式,使用的是http协议,head信息很大,有效数据占比低, 而        使用WebSocket方式,头信息很小,有效数据占比高.  2. 无浪费. 轮询方式有可能轮询10次,才碰到服务端数据更新,那么前9次都白轮询了,因为没有拿到变化     的数据. 而WebSocket是由服务器主动回发,来的都是新数据.     3. 实时性,考虑到服务器压力,使用轮询方式不可能很短的时间间隔,否则服务器压力太多,所以轮询时间

【WebSocket学习】

概念:WebSocket协议是基于TCP的一种新的网络协议.它实现了浏览器与服务器全双工(full-duplex)通信--允许服务器主动发送信息给客户端.WebSocket通信协议于2011年被IETF定为标准RFC 6455,并被RFC7936所补充规范. <?php class WebSocketServer { public $ws_server; CONST PORT = 8090; CONST HOST = '0.0.0.0'; CONST ENABLE_STATIC_HANDLER

关于WebSocket学习记录(一)

WebSocket技术的理解: WebSocket是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议. WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据.在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输.在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道.两者之间就直接可以数据互相传送