Python服务器:
import socket
import re
from base64 import b64encode
from hashlib import sha1
import base64
import struct
from queue import Queue
import threading
import select
def decodea(data):
buf = data
payload_start = 2
if len(buf) < 3:
return
b = (buf[0])
fin = b & 0x80
opcode = b & 0x0f
b2 = (buf[1])
mask = b2 & 0x80
length = b2 & 0x7f
if len(buf) < payload_start + 4:
return
elif length == 126:
length, = struct.unpack(">H", buf[2:4])
payload_start += 2
elif length == 127:
length, = struct.unpack(">I", buf[2:6])
payload_start += 4
if mask:
mask_bytes = [(b) for b in buf[payload_start:payload_start + 4]]
payload_start += 4
if len(buf) < payload_start + length:
return
payload = buf[payload_start:payload_start + length]
if mask:
unmasked = [mask_bytes[i % 4] ^ (b)
for b, i in zip(payload, range(len(payload)))]
payload = "".join([chr(c) for c in unmasked])
return [payload.encode('latin-1'), length]
def status(decoded):
status_ = ''
status_16 = 0
if(decoded[1] == 2):
for c in decoded[0]:
status_ += (str('%02x' % ord(chr(c))))
status_16 = int(status_, 16)
if(status_16 > 0):
cases = {
1000: "Normal Closure",
1001: "Going Away",
1002: "Protocol error",
1003: "Unsupported Data",
1004: "---Reserved----",
1005: "No Status Rcvd",
1006: "Abnormal Closure",
1007: "Invalid frame payload data",
1008: "Policy Violation",
1009: "Message Too Big",
1010: "Mandatory Ext.",
1011: "Internal Server Error",
1015: "TLS handshake"
}
if(status_16 in cases):
return status_16
return 0
def handshake(conn, globals__):
data = conn.recv(1024)
key = (re.search('Sec-WebSocket-Key:\s+(.*?)[\n\r]+', data.decode('utf-8'))
.groups()[0]
.strip())
sha1f = sha1()
sha1f.update(key.encode('utf-8') + globals__['GUID'].encode('utf-8'))
response_key = b64encode(sha1f.digest()).decode('utf-8')
response = '\r\n'.join(globals__['websocket_answer']).format(key=response_key)
conn.send(response.encode('utf-8'))
def socket_accept__(lock__, globals__):
lock__.acquire()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((globals__['socket_settings']['HOST'],globals__['socket_settings']['PORT']))
s.listen(globals__['socket_settings']['LISTEN'])
globals__['client_list'].append(s)
lock__.release()
while True:
lock__.acquire()
read_sockets,write_sockets,error_sockets = select.select(globals__['client_list'],[],[])
for sock in read_sockets:
if(sock == s):
conn, addr = s.accept()
handshake(conn, globals__)
globals__['client_list'].append(conn)
else:
for client in globals__['client_list']:
try:
client.settimeout(0.001)
data = client.recv(1024)
print(decodea(data)[0].decode('UTF-8'))
except(socket.timeout):
continue
lock__.release()
#thead_queue = Queue()
lock_ = threading.Lock()
globals_ = {
'GUID':'258EAFA5-E914-47DA-95CA-C5AB0DC85B11',
'websocket_answer': (
'HTTP/1.1 101 Switching Protocols',
'Upgrade: websocket',
'Connection: Upgrade',
'Sec-WebSocket-Accept: {key}\r\n\r\n'
),
'client_list': [],
'socket_settings': {
'HOST': '10.10.10.12',
'PORT': 8999,
'LISTEN': 200
},
'threads':[]
}
globals_['threads'].append(threading.Thread(target=socket_accept__, args=(lock_,globals_)))
globals_['threads'][0].setDaemon(True)
for threadi in globals_['threads']:
threadi.start()
for threadi in globals_['threads']:
threadi.join()
#thread2.join()
HTML5:
<!DOCTYPE html>
<html>
<head>
<title>test</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script type="text/javascript">
var s = new WebSocket('ws://10.10.10.12:8999');
s.onmessage = function(t){console.log(t); alert(t); };
s.onopen = function(){
s.send('hello from client');
s.send('my name is richard');
}
alert('load');
</script>
</head>
<body>
</body>
</html>
输出:
预期产出:
我确定这是因为client.settimout(0.001)
不够快?
我很遗憾,因为我不知道为什么会发生这种情况。
答案 0 :(得分:1)
由于通信问题没有消息丢失,只是它没有被解码。它与client.settimeout(0.001)
无关。
当来自客户端的两条或多条消息靠近(时间)时,两条消息将在一次data = client.recv(1024)
呼叫中接收。
这意味着data
可以包含多条消息。但是,decodea()
函数只处理一条消息。解码器完全忽略了任何其他消息,这就是您似乎丢失消息的原因。
您可以编写解码器来解码并返回多条消息,可能会将其更改为生成器函数,以便您可以依次yield
每条消息。然后,调用代码将遍历消息。
或者,您可以通过只读取前几个字节来检查传入消息,以确定消息的长度。然后从套接字读取剩余的字节并解码消息。在下一次迭代期间,任何其他消息都将被解码。
值得一提的是使用
迭代客户端列表for client in globals__['client_list']:
似乎错了,因为无论如何每个客户端只是一个套接字对象,并且您已经知道哪些套接字有待处理的数据:read_sockets
列表中的那些。您可以像这样编写代码:
while True:
lock__.acquire()
read_sockets,write_sockets,error_sockets = select.select(globals__['client_list'],[],[])
for sock in read_sockets:
if(sock == s):
conn, addr = s.accept()
handshake(conn, globals__)
globals__['client_list'].append(conn)
else:
data = sock.recv(1024)
print(decodea(data)[0].decode('UTF-8'))
但是你仍然需要弄清楚如何处理多个一起到达的消息 - 无论是在解码器中,还是确保你的代码一次只能读取一条消息。