求 Python 大佬解救

2020-11-06 20:22:39 +08:00
 1521815837

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

报错信息: 代码:

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()
2440 次点击
所在节点    Python
8 条回复
anjianshi
2020-11-06 20:28:11 +08:00
排查一下所有 + 号的地方?是不是在把字符串和 bytes 进行拼接。
并且看错误信息,是左侧字符串,右侧 bytes 。例如
a = 'abc'
b = b'def'
a + b
会报这个
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
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
2020-11-06 20:38:35 +08:00
@dd99iii 猜错了
CEBBCAT
2020-11-06 21:37:28 +08:00
明白了吗?#为什么而活?
ysc3839
2020-11-07 01:07:08 +08:00
“客户端断开连接”是在哪出现的?你的代码里没有呀?
qile1
2020-11-07 10:45:43 +08:00
msg=b''试试
dahuahua
2020-11-07 16:48:18 +08:00
为什么不打印日志

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/722527

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX