websocket原理
首先,Websocket是一个持久化的协议,相对于HTTP这种非持久的协议来说。
HTTP的生命周期通过 Request
来界定,也就是一个 Request
一个 Response
,那么在 HTTP1.0
中,这次HTTP请求就结束了。
在HTTP1.1中进行了改进,使得有一个keep-alive,也就是说,在一个HTTP连接中,可以发送多个Request,接收多个Response。但是请记住 Request = Response
, 在HTTP中永远是这样,也就是说一个request只能有一个response。而且这个response也是被动的,不能主动发起。
Websocket是基于HTTP协议的,或者说借用了HTTP的协议来完成一部分握手。
首先我们来看个典型的 Websocket
握手
GET /chat HTTP/1.1Host: server.example.comUpgrade: websocketConnection: UpgradeSec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==Sec-WebSocket-Protocol: chat, superchatSec-WebSocket-Version: 13Origin: http://example.com
熟悉HTTP的童鞋可能发现了,这段类似HTTP协议的握手请求中,多了几个东西。我会顺便讲解下作用。
Upgrade: websocketConnection: Upgrade
这个就是Websocket的核心了,告诉 Apache
、 Nginx
等服务器:注意啦,我发起的是Websocket协议,快点帮我找到对应的助理处理~不是那个老土的HTTP。
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==Sec-WebSocket-Protocol: chat, superchatSec-WebSocket-Version: 13
Sec-WebSocket-Key
是一个 Base64 encode
的值,这个是浏览器随机生成的,告诉服务器:泥煤,不要忽悠窝,我要验证尼是不是真的是Websocket助理。
然后, Sec_WebSocket-Protocol
是一个用户定义的字符串,用来区分同URL下,不同的服务所需要的协议。
最后, Sec-WebSocket-Version
是告诉服务器所使用的 Websocket Draft
(协议版本),在最初的时候,Websocket协议还在 Draft
阶段,各种奇奇怪怪的协议都有,而且还有很多期奇奇怪怪不同的东西,什么Firefox和Chrome用的不是一个版本之类的,后来做了统一。
然后服务器会返回下列东西,表示已经接受到请求, 成功建立Websocket啦!
HTTP/1.1 101 Switching ProtocolsUpgrade: websocketConnection: UpgradeSec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=Sec-WebSocket-Protocol: chat
这里开始就是HTTP最后负责的区域了,告诉客户,我已经成功切换协议啦~
Upgrade: websocketConnection: Upgrade
依然是固定的,告诉客户端即将升级的是 Websocket
协议,而不是mozillasocket,lurnarsocket或者shitsocket。
然后, Sec-WebSocket-Accept
这个则是经过服务器确认,并且加密过后的 Sec-WebSocket-Key
。
后面的, Sec-WebSocket-Protocol
则是表示最终使用的协议。
至此,HTTP已经完成它所有工作了。
实例
<html lang="en"><head> ???<meta charset="UTF-8"> ???<title>Title</title></head><body><h1>lujiacheng</h1><script> ???ws=new WebSocket("ws://127.0.0.1:8096") ???ws.onopen=function () { ???????alert(‘successful‘); ???????ws.send("Hellowww"); ???} ???ws.onmessage=function (event) { ???????alert(event.data) ???}</script></body></html>
import socketimport base64import hashlibimport struct# 向客户端发送消息def send_msg(conn,msg_bytes): ???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 ???print(msg) ???conn.send(msg) ???return Truedef get_websocket_message(str_header): ???header,body=str_header.split(b‘\r\n\r\n‘) ???header_dict={} ???headers=header.split(b‘\r\n‘) ???for str_spilt in headers: ??????????str_hd=str_spilt.split(b‘:‘) ??????????if len(str_hd)==2: ??????????????header_dict[str(str_hd[0],encoding=‘utf-8‘)]=str(str_hd[1],encoding=‘utf-8‘).strip() ???magic_string = ‘258EAFA5-E914-47DA-95CA-C5AB0DC85B11‘ ???values=header_dict[‘Sec-WebSocket-Key‘]+magic_string ???ac=base64.b64encode(hashlib.sha1(values.encode(‘utf-8‘)).digest()) ???request_tpl="HTTP/1.1 101 Switching Protocols\r\n" ????????????????"Upgrade: websocket\r\n" ????????????????"Connection: Upgrade\r\n" ????????????????"Sec-WebSocket-Accept: %s\r\n\r\n" %(str(ac,encoding=‘utf-8‘)) ???return request_tpl.encode(‘utf-8‘)sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)sock.bind((‘127.0.0.1‘,8096))sock.listen(5)# 等待用户连接conn,addr=sock.accept()# 握手消息data=conn.recv(8096)# 获取握手消息,magic_string,shal加密# 发送给客户端recv=get_websocket_message(data)conn.send(recv)# 建立成功后,接收客户端发过来的消息info = conn.recv(1024)# 解析客户端发过来的数据while True: ???# payload_len决定数据头和数据所占的位数 ???# payload_len等于126,要在往后移2字节,即16bit ???# payload_len等于127,要在往后移8字节,即64bit ???# mask解码 ???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 in range(len(decoded)): ???????chunk=decoded[i] ^ mask[i % 4] ???????bytes_list.append(chunk) ???body=str(bytes_list,encoding="utf-8") ???print(body) ???text=input(">>>") ???send_msg(conn,bytes(text,encoding="utf-8"))
基于socket实现websocket服务
原文地址:https://www.cnblogs.com/lujiacheng-Python/p/10293830.html