websocket python3实现_python3 实现 websocket server 解决中文乱码

一、什么是websocket

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

在WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。

当你获取 Web Socket 连接后,你可以通过 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据。      -----------------    出自菜鸟教程

二、客户端请求报文

客户端请求的链接:ws://localhost:8080

和传统http报文不同的地方:

Connection: Upgrade

Upgrade: websocket    -----   表示发起的是websocket协议

Sec-WebSocket-Key: TD7emWUct4iW4vddYWbMqQ==   ------   由浏览器随机生成,提供基本的防护

Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits    ----    协议的扩展

Sec-WebSocket-Version: 13   ----   版本号

三、服务器接收请求报文

服务器收到请求报文后,会发起tcp的三次握手,和客户端建立链接,这个地方和tcpsocket基本一样。

#创建基于tcp的服务器

serverSocket =socket.socket(socket.AF_INET, socket.SOCK_STREAM)

serverSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,1)

host=(HOST, PORT)

serverSocket.bind(host)

serverSocket.listen(128)print("服务器运行, 等待用户链接")whileTrue:#print("getting connection")

clientSocket, addressInfo =serverSocket.accept()#print("get connected")

request = clientSocket.recv(2048)print(request.decode())#获取Sec-WebSocket-Key

ret = re.search(r"Sec-WebSocket-Key: (.*==)", str(request.decode()))ifret:

key= ret.group(1)else:returnSec_WebSocket_Key= key +MAGIC_STRING#print("key ", Sec_WebSocket_Key)

#将Sec-WebSocket-Key先进行sha1加密,转成二进制后在使用base64加密

response_key = base64.b64encode(hashlib.sha1(bytes(Sec_WebSocket_Key, encoding="utf8")).digest())

response_key_str=str(response_key)

response_key_str= response_key_str[2:30]#print(response_key_str)

#构建websocket返回数据

response = HANDSHAKE_STRING.replace("{1}", response_key_str).replace("{2}", HOST + ":" +str(PORT))

clientSocket.send(response.encode())#print("send the hand shake data")

四、因为websocket是基于tcp的全双工通信协议,所以,他可以一边接收,一边发送

1、接收并解析websocket报文

b'\x81\x84\xa3l\xcf\x10\x92^\xfc$'

客户端发送到server的websocket的报文分为四个部分:

a、固定部分‘\81’

b、报文内容长度

c、掩码 b'\xa3l\xcf\x10'

d、报文内容   b'\x92^\xfc$'

defrecv_data(clientSocket):try:

info= clientSocket.recv(2048)if notinfo:return

except:return

else:

code_len= info[1] & 0x7f

if code_len == 0x7e:

extend_payload_len= info[2:4]

mask= info[4:8]

decoded= info[8:]elif code_len == 0x7f:

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 inrange(len(decoded)):

chunk= decoded[i] ^ mask[i % 4]

bytes_list.append(chunk)

raw_str= str(bytes_list, encoding="utf-8")print(raw_str)

2、server端发送数据

server端发送数据分为三个部分

a、固定部分‘\81’

b、报文长度

c、报文内容

struct用法:

Format C Type Python type Standard size Notes

x pad byte no value

c char bytes of length1 1b signed char integer1 (1),(3)

B unsigned char integer1 (3)

? _Bool bool1 (1)

h short integer2 (3)

H unsigned short integer2 (3)

i int integer4 (3)

I unsigned int integer4 (3)

l long integer4 (3)

L unsigned long integer4 (3)

q long long integer8 (2), (3)

Q unsigned long long integer8 (2), (3)

n ssize_t integer (4)

N size_t integer (4)

e (7) float 2 (5)

f float float4 (5)

d double float8 (5)

s char[] bytes

p char[] bytes

P void* integer (6)

Character Byte order Size Alignment

@ native native native=native standard none< little-endian standard none> big-endian standard none

! network (= big-endian) standard none

服务端发送数据代码:

defsend_data(clientSocket):

data= "need to send messages中文"token= b'\x81'length=len(data.encode())if length<=125:

token+= struct.pack('B', length)elif length <= 0xFFFF:

token+= struct.pack('!BH', 126, length)else:

token+= struct.pack('!BQ', 127, length)

data= token +data.encode()

clientSocket.send(data)

全部代码:

py:

importsocketimportbase64importhashlibimportreimportthreadingimportstruct

HOST= "localhost"PORT= 8080MAGIC_STRING= '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'HANDSHAKE_STRING= "HTTP/1.1 101 Switching Protocols\r\n"\"Upgrade:websocket\r\n"\"Connection: Upgrade\r\n"\"Sec-WebSocket-Accept: {1}\r\n"\"WebSocket-Location: ws://{2}/chat\r\n"\"WebSocket-Protocol:chat\r\n\r\n"

defrecv_data(clientSocket):try:

info= clientSocket.recv(2048)if notinfo:return

except:return

else:print(info)

code_len= info[1] & 0x7f

if code_len == 0x7e:

extend_payload_len= info[2:4]

mask= info[4:8]

decoded= info[8:]elif code_len == 0x7f:

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()print(mask)print(decoded)for i inrange(len(decoded)):

chunk= decoded[i] ^ mask[i % 4]

bytes_list.append(chunk)

raw_str= str(bytes_list, encoding="utf-8")print(raw_str)defsend_data(clientSocket):

data= "need to send messages中文"token= b'\x81'length=len(data.encode())if length<=125:

token+= struct.pack('B', length)elif length <= 0xFFFF:

token+= struct.pack('!BH', 126, length)else:

token+= struct.pack('!BQ', 127, length)

data= token +data.encode()

clientSocket.send(data)defhandshake(serverSocket):whileTrue:#print("getting connection")

clientSocket, addressInfo =serverSocket.accept()#print("get connected")

request = clientSocket.recv(2048)print(request.decode())#获取Sec-WebSocket-Key

ret = re.search(r"Sec-WebSocket-Key: (.*==)", str(request.decode()))ifret:

key= ret.group(1)else:returnSec_WebSocket_Key= key +MAGIC_STRING#print("key ", Sec_WebSocket_Key)

#将Sec-WebSocket-Key先进行sha1加密,转成二进制后在使用base64加密

response_key = base64.b64encode(hashlib.sha1(bytes(Sec_WebSocket_Key, encoding="utf8")).digest())

response_key_str=str(response_key)

response_key_str= response_key_str[2:30]#print(response_key_str)

#构建websocket返回数据

response = HANDSHAKE_STRING.replace("{1}", response_key_str).replace("{2}", HOST + ":" +str(PORT))

clientSocket.send(response.encode())#print("send the hand shake data")

t1 = threading.Thread(target = recv_data, args =(clientSocket,))

t1.start()

t2= threading.Thread(target = send_data, args =(clientSocket,))

t2.start()defmain():#创建基于tcp的服务器

serverSocket =socket.socket(socket.AF_INET, socket.SOCK_STREAM)

serverSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,1)

host=(HOST, PORT)

serverSocket.bind(host)

serverSocket.listen(128)print("服务器运行, 等待用户链接")#调用监听

handshake(serverSocket)if __name__ == "__main__":

main()

html:

w
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值