首先明确几点:php
1. websocket是一种协议。是html5的一种新协议; 2. 与http的区别是,它是一种双向通讯协议,服务器和客户端都能主动向对方发送或接受数据; 3. websocket须要进行握手链接以后才能进行通讯;
由此咱们便知道了websocket诞生的意义:html
传统的HTTP请求方式,是客户端发送请求服务端响应的形式,这种方式在应对信息变化不是很频繁的应用时还能较好的应对,可是对于实时要求/海量并发的应用来讲显得不是很给力,尤为在当前业界移动的互联网蓬勃发展的趋势下,高并发与用户实时响应是web应用常常面临的问题,好比金融证券的实时信息,web导航应用中的地理位置获取,社交网络的实时消息推送等.html5
基于HTTP,咱们也有实时通信的方案,好比轮询,好比使用flash的socket,可是这些都是非标准的,并且代价较大,HTML5的标准化组织须要针对实时通信的应用场景提供一套业界赞成的规范,那就是websocket.linux
socket的概念最初出如今linux网络编程中,socket是在应用层和传输层之间的一个抽象层,他把TCP链接创建和释放的过程惊醒了一层封装,提供出接口给应用层.web
socket是如何与对应网络中的进程进行通讯的呢?编程
咱们知道两个进程若是须要进行通信最基本的一个前提能可以惟一的标示一个进程,在本地进程通信中咱们可使用PID来惟一标示一个进程,但PID只在本地惟一,网络中的两个进程PID冲突概率很大,这是后咱们须要另辟蹊径了,咱们知道ip层的IP地址能够惟一标示主机,而TCP层协议和端口能够惟一标示一个进程,这样咱们能够利用IP地址+协议+端口号惟一标示网络中的一个进程.浏览器
那么在进行socket接口调用了时候,传递上述惟一标示以后,生成响应的协议请求,双向通讯就能经过socket进行了.安全
websocket的做用也是模仿socket的通讯能力,可是不一样的是,它自己是一种协议,浏览器和服务端会对这种协议进行解析,他是基于基础TCP链接的,因此自己它是具备创建双向链接的能力的,只不过具体的数据传输方式和一些针对web实时通信的特性须要在websocket中进行定义.服务器
传统的HTTP请求方式:websocket
websocket的通讯方式
能够看到,HTTP请求每次与服务端交互必定的从新创建链接,可是websocket协议之须要双方经过握手创建链接,在链接释放以前,客户端和服务端能够相互接受和传递数据,由于双方经过协议是知道创建websocket链接各自进程的端口号.
在客户端中,咱们须要使用websocket对象,去链接ws://这样的服务端url,这样客户端就会自动解析并识别websocket请求从而和服务端经过握手创建链接.
GET /webfin/websocket/ HTTP/1.1 Host: localhost Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: xqBt3ImNzJbYqRINxEFlkg== Origin: http://localhost:8080 Sec-WebSocket-Version: 13
其中,"Sec-WebSocket-Key"是websocket客户端发送的一个base64编码的密文,要求服务端必须返回一个对应加密的"Sec-Socket-Accept"应答,不然客户端会抛出"Error during WebSocket handshake"错误,并关闭链接.
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: K7DJLdLooIwIG/MOpvWFB3y3FE8=
"Sec-WebSocket-Accept"的值是服务端采用与客户端一直的秘钥计算出来后返回客户端的,"HTTP/1.1 101 Switching Protocols"表示服务端接受WebSocket链接握手成功,后续就能够进行TCP通信了.
要实现websocket,必须客户端和服务端都要支持这个协议.
Tomcat在新版本中提供了WebSocketServle对象,用于支持websocket,php确定也有本身的websocket封装.
而在客户端HTML5提佛那个了标准的websocket API ,demo实现以下:
var ws = new WebSocket(“ws://echo.websocket.org”); ws.onopen = function(){ws.send(“Test!”); }; ws.onmessage = function(evt){console.log(evt.data);ws.close();}; ws.onclose = function(evt){console.log(“WebSocketClosed!”);}; ws.onerror = function(evt){console.log(“WebSocketError!”);}; ws.send("hello");//向服务器发送消息
第一行代码是在申请一个websocket对象,参数是须要链接的服务器端的地址,同HTTP协议开头同样,websocket协议的url使用ws://开头,另外安全的websocket协议使用ws://开头
第二行到第五行为websocket对象注册消息的处理函数,websocket对象一共支持四个消息 onopen, onmessage, onclose, onerror,有了这四个事件,咱们就能够很容易很轻松驾驭websocket.
当Browser和websocketserver链接成功后,会触发onopen消息,若是链接失败,发送.接收数据失败或者处理数据出现错误,browser会触发onerror消息;当browser接收到websocketserver发送过来的数据时,就会触发onmessage消息,参数evt中包含server传输过来的数据;当browser接收到websocket端发送的关闭链接请求时,就触发onclose消息,咱们能够看出全部的操做都是采用一步回调的方法触发,这样不会阻塞UI,能够得到更快的响应时间,更好的用户体验.
import struct msg_bytes = "the emperor has not been half-baked in the early days of the collapse of the road, today down three points, yizhou weakness, this serious crisis autumn".encode("utf8") token = b"\x81" # + 数据长度/运算位 + mask/数据长度 + mask/数据 + 数据 length = len(msg_bytes) if length < 126: token += struct.pack("B", length) elif length == 126: token += struct.pack("!BH", 126, length) else: token += struct.pack("!BQ", 127, length) msg = token + msg_bytes print(msg)
#b'\x81\x89\xf3\x99\x81-\x15\x05\x01\xcbO\x1be\x97]' #b'\x81\x85s\x92a\x10\x1b\xf7\r|\x1c' #b'\x81\x83H\xc0x\xa6y\xf2K' hashstr = b'\x81\x85s\x92a\x10\x1b\xf7\r|\x1c' # b'\x81 \x85s \x92a\x10\x1b\xf7 \r|\x1c' <126 # \x85s = 5 # print(chushibiao[1],chushibiao[1]&127) # print(chushibiao[2:4],chushibiao[4:8]) # 将第二个字节也就是 \x83 第9-16位 进行与127进行位运算 payload = hashstr[1] & 127 print(payload) if payload == 127: extend_payload_len = hashstr[2:10] mask = hashstr[10:14] decoded = hashstr[14:] # 当位运算结果等于127时,则第3-10个字节为数据长度 # 第11-14字节为mask 解密所需字符串 # 则数据为第15字节至结尾 if payload == 126: extend_payload_len = hashstr[2:4] mask = hashstr[4:8] decoded = hashstr[8:] # 当位运算结果等于126时,则第3-4个字节为数据长度 # 第5-8字节为mask 解密所需字符串 # 则数据为第9字节至结尾 if payload <= 125: extend_payload_len = None mask = hashstr[2:6] decoded = hashstr[6:] # 当位运算结果小于等于125时,则这个数字就是数据的长度 # 第3-6字节为mask 解密所需字符串 # 则数据为第7字节至结尾 str_byte = bytearray() # b'\x81 \x85s \x92a\x10\x1b \xf7\r|\x1c' <126 for i in range(len(decoded)): # 0 \xf7 ^ \x92a 1 \r ^ \x10 \x1c ^ \x1b byte = decoded[i] ^ mask[i % 4] str_byte.append(byte) print(str_byte.decode("utf8"))