python websocket服务器_python之websocket

一、websocket

WebSocket协议是基于TCP的一种新的协议。WebSocket最初在HTML5规范中被引用为TCP连接,作为基于TCP的套接字API的占位符。它实现了浏览器与服务器全双工(full-duplex)通信。其本质是保持TCP连接,在浏览器和服务端通过Socket进行通信。

本文将使用Python编写Socket服务端,一步一步分析请求过程!!!

1. 启动服务端

importsocket

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

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

sock.bind(('127.0.0.1', 8002))

sock.listen(5)#等待用户连接

conn, address =sock.accept()

...

...

...

启动Socket服务器后,等待用户【连接】,然后进行收发数据。

2. 客户端连接

...

当客户端向服务端发送连接请求时,不仅连接还会发送【握手】信息,并等待服务端响应,至此连接才创建成功!

3. 建立连接【握手】

importsocket

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

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

sock.bind(('127.0.0.1', 8002))

sock.listen(5)#获取客户端socket对象

conn, address =sock.accept()#获取客户端的【握手】信息

data = conn.recv(1024)

...

...

...

conn.send('响应【握手】信息')

请求和响应的【握手】信息需要遵循规则:

从请求【握手】信息中提取 Sec-WebSocket-Key

利用magic_string 和 Sec-WebSocket-Key 进行hmac1加密,再进行base64加密

将加密结果响应给客户端

注:magic string为:258EAFA5-E914-47DA-95CA-C5AB0DC85B11

请求【握手】信息为:

GET /chatsocket HTTP/1.1Host:127.0.0.1:8002Connection: Upgrade

Pragma: no-cache

Cache-Control: no-cache

Upgrade: websocket

Origin: http://localhost:63342Sec-WebSocket-Version: 13Sec-WebSocket-Key: mnwFxiOlctXFN/DeMt1Amg==Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits

...

...

提取Sec-WebSocket-Key值并加密:

importsocketimportbase64importhashlibdefget_headers(data):"""将请求头格式化成字典

:param data:

:return:"""header_dict={}

data= str(data, encoding='utf-8')for i in data.split('\r\n'):print(i)

header, body= data.split('\r\n\r\n', 1)

header_list= header.split('\r\n')for i inrange(0, len(header_list)):if i ==0:if len(header_list[i].split(' ')) == 3:

header_dict['method'], header_dict['url'], header_dict['protocol'] = header_list[i].split(' ')else:

k, v= header_list[i].split(':', 1)

header_dict[k]=v.strip()returnheader_dict

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

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

sock.bind(('127.0.0.1', 8002))

sock.listen(5)

conn, address=sock.accept()

data= conn.recv(1024)

headers= get_headers(data) #提取请求头信息#对请求头中的sec-websocket-key进行加密

response_tpl = "HTTP/1.1 101 Switching Protocols\r\n"\"Upgrade:websocket\r\n"\"Connection: Upgrade\r\n"\"Sec-WebSocket-Accept: %s\r\n"\"WebSocket-Location: ws://%s%s\r\n\r\n"magic_string= '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'value= headers['Sec-WebSocket-Key'] +magic_string

ac= base64.b64encode(hashlib.sha1(value.encode('utf-8')).digest())

response_str= response_tpl % (ac.decode('utf-8'), headers['Host'], headers['url'])#响应【握手】信息

conn.send(bytes(response_str, encoding='utf-8'))

...

...

...

View Code

4.客户端和服务端收发数据

客户端和服务端传输数据时,需要对数据进行【封包】和【解包】。客户端的JavaScript类库已经封装【封包】和【解包】过程,但Socket服务端需要手动实现。

第一步:获取客户端发送的数据【解包】

info = conn.recv(8096)

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

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

bytes_list.append(chunk)

body= str(bytes_list, encoding='utf-8')print(body)

基于Python实现解包过程(未实现长内容)

解包详细过程:

第二步:向客户端发送数据【封包】

defsend_msg(conn, msg_bytes):"""WebSocket服务端向客户端发送消息

:param conn: 客户端连接到服务器端的socket对象,即: conn,address = socket.accept()

:param msg_bytes: 向客户端发送的字节

:return:"""

importstruct

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

conn.send(msg)return True

你可能感兴趣的:(python,websocket服务器)