zoukankan      html  css  js  c++  java
  • 基于socket实现websocket服务

    websocket原理

    首先,Websocket是一个持久化的协议,相对于HTTP这种非持久的协议来说。

    HTTP的生命周期通过 Request 来界定,也就是一个 Request 一个 Response ,那么在 HTTP1.0 中,这次HTTP请求就结束了。

    HTTP1.1中进行了改进,使得有一个keep-alive,也就是说,在一个HTTP连接中,可以发送多个Request,接收多个Response。但是请记住 Request = Response, 在HTTP中永远是这样,也就是说一个request只能有一个response。而且这个response也是被动的,不能主动发起。

    Websocket是基于HTTP协议的,或者说借用了HTTP的协议来完成一部分握手。

    首先我们来看个典型的 Websocket 握手

    GET /chat HTTP/1.1
    Host: server.example.com
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
    Sec-WebSocket-Protocol: chat, superchat
    Sec-WebSocket-Version: 13
    Origin: http://example.com

    熟悉HTTP的童鞋可能发现了,这段类似HTTP协议的握手请求中,多了几个东西。我会顺便讲解下作用。

    Upgrade: websocket
    Connection: Upgrade

    这个就是Websocket的核心了,告诉 Apache 、 Nginx 等服务器:注意啦,我发起的是Websocket协议,快点帮我找到对应的助理处理~不是那个老土的HTTP。

    Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
    Sec-WebSocket-Protocol: chat, superchat
    Sec-WebSocket-Version: 13

    Sec-WebSocket-Key 是一个 Base64 encode 的值,这个是浏览器随机生成的,告诉服务器:泥煤,不要忽悠窝,我要验证尼是不是真的是Websocket助理。

    然后, Sec_WebSocket-Protocol 是一个用户定义的字符串,用来区分同URL下,不同的服务所需要的协议

    最后, Sec-WebSocket-Version 是告诉服务器所使用的 Websocket Draft (协议版本),在最初的时候,Websocket协议还在 Draft 阶段,各种奇奇怪怪的协议都有,而且还有很多期奇奇怪怪不同的东西,什么Firefox和Chrome用的不是一个版本之类的,后来做了统一。

    然后服务器会返回下列东西,表示已经接受到请求, 成功建立Websocket啦!

    HTTP/1.1 101 Switching Protocols
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
    Sec-WebSocket-Protocol: chat

    这里开始就是HTTP最后负责的区域了,告诉客户,我已经成功切换协议啦~

    Upgrade: websocket
    Connection: Upgrade

    依然是固定的,告诉客户端即将升级的是 Websocket 协议,而不是mozillasocket,lurnarsocket或者shitsocket。

    然后, Sec-WebSocket-Accept 这个则是经过服务器确认,并且加密过后的 Sec-WebSocket-Key 。

    后面的, Sec-WebSocket-Protocol 则是表示最终使用的协议。

    至此,HTTP已经完成它所有工作了。

    实例

    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <h1>lujiacheng</h1>
    <script>
        ws=new WebSocket("ws://127.0.0.1:8096")
        ws.onopen=function () {
            alert('successful');
            ws.send("Hellowww");
        }
    
        ws.onmessage=function (event) {
            alert(event.data)
        }
    </script>
    
    </body>
    </html>
    client.html
    import socket
    import base64
    import hashlib
    import struct
    
    # 向客户端发送消息
    def send_msg(conn,msg_bytes):
        token=b"x81"
        length=len(msg_bytes)
        if length<126:
            token+=struct.pack("B",length)
        elif length<0xFFFF:
            token+=struct.pack("!BH",126,length)
        else:
            token+=struct.pack("!BQ",127,length)
        msg=token+msg_bytes
        print(msg)
        conn.send(msg)
        return True
    
    
    def get_websocket_message(str_header):
        header,body=str_header.split(b'
    
    ')
        header_dict={}
        headers=header.split(b'
    ')
        for str_spilt in headers:
               str_hd=str_spilt.split(b':')
               if len(str_hd)==2:
                   header_dict[str(str_hd[0],encoding='utf-8')]=str(str_hd[1],encoding='utf-8').strip()
        magic_string = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
        values=header_dict['Sec-WebSocket-Key']+magic_string
        ac=base64.b64encode(hashlib.sha1(values.encode('utf-8')).digest())
    
        request_tpl="HTTP/1.1 101 Switching Protocols
    " 
                    "Upgrade: websocket
    " 
                    "Connection: Upgrade
    " 
                    "Sec-WebSocket-Accept: %s
    
    " %(str(ac,encoding='utf-8'))
    
        return request_tpl.encode('utf-8')
    
    
    sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    sock.bind(('127.0.0.1',8096))
    
    sock.listen(5)
    
    # 等待用户连接
    conn,addr=sock.accept()
    
    # 握手消息
    data=conn.recv(8096)
    
    # 获取握手消息,magic_string,shal加密
    # 发送给客户端
    recv=get_websocket_message(data)
    conn.send(recv)
    
    # 建立成功后,接收客户端发过来的消息
    info = conn.recv(1024)
    
    # 解析客户端发过来的数据
    while True:
        # payload_len决定数据头和数据所占的位数
        # payload_len等于126,要在往后移2字节,即16bit
        # payload_len等于127,要在往后移8字节,即64bit
        # mask解码
        payload_len=info[1] & 127
        if payload_len==126:
            extend_payload_len=info[2:4]
            mask=info[4:8]
            decoded=info[8:]
        elif payload_len==127:
            extend_payload_len = info[2:10]
            mask = info[10:14]
            decoded = info[14:]
        else:
            extend_payload_len = None
            mask = info[2:6]
            decoded = info[6:]
    
        bytes_list=bytearray()
        for i in range(len(decoded)):
            chunk=decoded[i] ^ mask[i % 4]
            bytes_list.append(chunk)
    
        body=str(bytes_list,encoding="utf-8")
        print(body)
    
        text=input(">>>")
        send_msg(conn,bytes(text,encoding="utf-8"))
    WebSocket.py
  • 相关阅读:
    [原创] 毕设---在myeclipes中安装Hadoop开发插件
    [转]Linux下RPM软件包的安装及卸载 yum操作
    [转]结构化、半结构化和非结构化数据
    [转]这5种必知的大数据处理框架技术
    [转]浅谈Hive vs. HBase 区别在哪里
    前端资源整理
    每个程序员都应该知道的10大基础算法
    Python Day14(HTML)
    Python Day13(yaml)
    Python Day12(补充)
  • 原文地址:https://www.cnblogs.com/lujiacheng-Python/p/10293830.html
Copyright © 2011-2022 走看看