V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
1521815837
V2EX  ›  Python

求 Python 大佬解救

  •  
  •   1521815837 · 2020-11-06 20:22:39 +08:00 · 2407 次点击
    这是一个创建于 1478 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近做项目写了一个小 websocket 服务器但是有报错我自己没法搞定求大神解救

    报错信息: BhdG7V.png 代码:

    import socket
    import time
    import hashlib
    import base64
    import struct
    import threading
    import chardet
    
    connlist = []
    s = socket.socket()         
    host = "0.0.0.0"
    port = 1999                
    s.bind((host, port))       
    s.listen(500) 
    
    def getheads(data):
        data = data.decode()
        datasplit = data.split("\r\n")
        datasplit = datasplit[1:-2]
        headslist = {}
        for i in datasplit:
            k,v = i.split(":",1)
            headslist[k] = v.replace(' ','')
        return headslist
    
    def _get_data(info, setcode):
        payload_len = info[1] & 127
        fin = 1 if info[0] & 128 == 128 else 0
        opcode = info[0] & 15
        if payload_len == 126:
            mask = info[4:8]
            decoded = info[8:]
        elif payload_len == 127:
            mask = info[10:14]
            decoded = info[14:]
        else:
            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)
        if opcode == 0x00:
            opcode = setcode
        if opcode == 0x01:
            body = str(bytes_list, encoding='utf-8',errors='ignore')
            return fin, opcode, body
        else:
            body = decoded
            return fin, opcode, body
                
    def recv(conn):
        msg = ''
        opcode = 0x00
        while True:
            raw_data = b''
            while True:
                section = conn.recv(1024)
                raw_data += section
                if len(section) < 1024:
                    break
            fin, _opcode, fragment = _get_data(raw_data,opcode)
            opcode = _opcode if _opcode != 0x00 else opcode
            msg += fragment
            if fin == 1: 
                break
        return msg
        
    def send(conn,msg,fin=True):
        data = struct.pack('B', 129) if fin else struct.pack('B', 0)
        msg_len = len(msg)
        if msg_len <= 125:
            data += struct.pack('B', msg_len)
        elif msg_len <= (2**16 - 1):
            data += struct.pack('!BH', 126, msg_len)
        elif msg_len <= (2**64 - 1):
            data += struct.pack('!BQ', 127, msg_len)
        else:
            while True:
                fragment = msg[:(2**64 - 1)]
                msg -= fragment
                if msg > (2**64 - 1):
                    conn.send(fragment, False)
                else:
                    conn.send(fragment)
        data += bytes(msg,encoding='utf-8',errors='ignore')
        conn.send(data)
    
    
    def shakehands(conn):
        data = conn.recv(1024)
        heads = getheads(data)
        msg = heads["Sec-WebSocket-Key"]
        key = msg + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
        ser_key = hashlib.sha1(key.encode('utf-8')).digest()
        token = base64.b64encode(ser_key)
        message = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "+bytes.decode(token)+"\r\nWebSocket-Origin: "+str(heads["Origin"])+"\r\nWebSocket-Location: ws://"+str(heads["Host"])+"\r\n\r\n"
        conn.send(message.encode())
        connlist.append(conn)
    
    def websockethandle(conn,addr):
        shakehands(conn) 
        ip,port = addr
        print(ip+" 连入")
        print("当前用户数:"+str(len(connlist)))
        while True:
            try: 
                data= recv(conn)
            except Exception as e:
                print(e)
                print(ip+" 断开")
                conn.close()
                connlist.remove(conn)
                print("当前用户数:"+str(len(connlist)))
                break
            for i in connlist:
                if i != conn:
                    send(i,data)
                        
    while True:
        conn,addr = s.accept()
        threading.Thread(target=websockethandle,args=(conn,addr,)).start()
    
    8 条回复    2020-11-07 16:48:18 +08:00
    anjianshi
        1
    anjianshi  
       2020-11-06 20:28:11 +08:00
    排查一下所有 + 号的地方?是不是在把字符串和 bytes 进行拼接。
    并且看错误信息,是左侧字符串,右侧 bytes 。例如
    a = 'abc'
    b = b'def'
    a + b
    会报这个
    anjianshi
        2
    anjianshi  
       2020-11-06 20:35:45 +08:00
    粗看了一下,你看是不是这样的问题:
    1. def recv(conn) 里调用 _get_data(raw_data) 时传入的 raw_data 是 bytes
    2. def _get_data(info, setcode) 里收到的 info 是 bytes,函数里的 decoded 变量是基于 info 的,所以也是 bytes,
    然后函数返回值 body 在最下面的一个 if 分支,就等于 decoded 变量,所以返回的也是 bytes
    3. def recv(conn) 获取到 _get_data() 的返回值并写入 fragment 变量,但按上面的流程,fragment 是一个 bytes
    4. def recv(conn) 执行了 msg += fragment,msg 是 str,fragment 是 bytes,最终报错
    dd99iii
        3
    dd99iii  
       2020-11-06 20:36:37 +08:00
    message = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "+bytes.decode(token)+"\r\nWebSocket-Origin: "+str(heads["Origin"])+"\r\nWebSocket-Location: ws://"+str(heads["Host"])+"\r\n\r\n"

    我猜这个是 bytes:
    bytes.decode(token)
    dd99iii
        4
    dd99iii  
       2020-11-06 20:38:35 +08:00
    @dd99iii 猜错了
    CEBBCAT
        5
    CEBBCAT  
       2020-11-06 21:37:28 +08:00 via Android
    明白了吗?#为什么而活?
    ysc3839
        6
    ysc3839  
       2020-11-07 01:07:08 +08:00
    “客户端断开连接”是在哪出现的?你的代码里没有呀?
    qile1
        7
    qile1  
       2020-11-07 10:45:43 +08:00 via Android
    msg=b''试试
    dahuahua
        8
    dahuahua  
       2020-11-07 16:48:18 +08:00
    为什么不打印日志
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1064 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 19:25 · PVG 03:25 · LAX 11:25 · JFK 14:25
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.