websocket原理html
首先,Websocket是一个持久化的协议,相对于HTTP这种非持久的协议来讲。web
HTTP的生命周期经过 Request
来界定,也就是一个 Request
一个 Response
,那么在 HTTP1.0
中,此次HTTP请求就结束了。浏览器
在HTTP1.1中进行了改进,使得有一个keep-alive,也就是说,在一个HTTP链接中,能够发送多个Request,接收多个Response。可是请记住 Request = Response
, 在HTTP中永远是这样,也就是说一个request只能有一个response。并且这个response也是被动的,不能主动发起。服务器
Websocket是基于HTTP协议的,或者说借用了HTTP的协议来完成一部分握手。websocket
首先咱们来看个典型的 Websocket
握手app
GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13 Origin: http://example.com
熟悉HTTP的童鞋可能发现了,这段相似HTTP协议的握手请求中,多了几个东西。我会顺便讲解下做用。socket
Upgrade: websocket Connection: Upgrade
这个就是Websocket的核心了,告诉 Apache
、 Nginx
等服务器:注意啦,我发起的是Websocket协议,快点帮我找到对应的助理处理~不是那个老土的HTTP。ide
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13
Sec-WebSocket-Key
是一个 Base64 encode
的值,这个是浏览器随机生成的,告诉服务器:泥煤,不要忽悠窝,我要验证尼是否是真的是Websocket助理。加密
而后, Sec_WebSocket-Protocol
是一个用户定义的字符串,用来区分同URL下,不一样的服务所须要的协议。spa
最后, Sec-WebSocket-Version
是告诉服务器所使用的 Websocket Draft
(协议版本),在最初的时候,Websocket协议还在 Draft
阶段,各类奇奇怪怪的协议都有,并且还有不少期奇奇怪怪不一样的东西,什么Firefox和Chrome用的不是一个版本之类的,后来作了统一。
而后服务器会返回下列东西,表示已经接受到请求, 成功创建Websocket啦!
HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat
这里开始就是HTTP最后负责的区域了,告诉客户,我已经成功切换协议啦~
Upgrade: websocket Connection: 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 socket import base64 import hashlib import 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 True def 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"))