The specific WebSocket introduction is visible Http://zh.wikipedia.org/wiki/WebSocket
Here, how to use Python to communicate with the front-end JS.
WebSocket use the HTTP protocol to complete the handshake, do not direct websocket communication via HTTP.
So, using WebSocket is roughly two steps: using HTTP handshake, communication.
JS processing websocket to use the WS module, Python processing uses the socket module to establish a TCP connection, than the general socket, only one handshake and data processing steps.
Shake hands
Process
Package format
The JS client first sends a handshake packet to the server-side Python, in the following format:
Get/chat http/1.1
Host:server.example.com
upgrade:websocket
connection:upgrade
sec-websocket-key:dghlihnhbxbszsbub25jzq==
origin:http://example.com
sec-websocket-protocol:chat, Superchat
sec-websocket-version:13
Server Response Package Format:
http/1.1 switching Protocols
upgrade:websocket
connection:upgrade
sec-websocket-accept: s3pplmbitxaq9kygzzhzrbk+xoo=
Sec-websocket-protocol:chat
Where the Sec-websocket-key is random, the server constructs a SHA-1 information digest with these data.
The method is: Key+migic, SHA-1 encryption, base-64 encryption, as follows:
Processing code in Python
magic_string = ' 258eafa5-e914-47da-95ca-c5ab0dc85b11 '
res_key = Base64.b64encode (HASHLIB.SHA1 (Sec_key + MAGIC_ STRING). Digest ())
Handshake Complete Code
JS End
JS in the processing of websocket classes, after initialization automatically send a handshake package, as follows:
var socket = new WebSocket (' ws://localhost:3368 ');
Python End
Python accepts a handshake string with a socket and sends it after processing
HOST = ' localhost ' PORT = 3368 magic_string = ' 258eafa5-e914-47da-95ca-c5ab0dc85b11 ' handshake_string = ' http/1.1-Swi tching 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" def handshake (Con): #con
For the socket #这里省略监听 with socket,accept (), the Accept code is visible blog:http://blog.csdn.net/ice110956/article/details/29830627 headers = {} shake = CON.RECV (1024) if not Len (Shake): Return False header, data = Shake.split (' \r\n\r\n ', 1) fo R line in Header.split (' \ r \ n ') [1:]: Key, val = Line.split (': ', 1) headers[key] = val if ' Sec-websocket-key ' not in
Headers:print (' This socket isn't websocket, client close. ') Con.close () return False Sec_key = headers[' Sec-websocket-key '] Res_key = Base64.b64encode (HASHLIB.SHA1 (Sec_key + MA gic_string). Digest ()) Str_handshake = Handshake_string.replace (' {1} ', Res_key). Replace(' {2} ', HOST + ': ' + str (PORT) ') Print Str_handshake con.send (str_handshake) return True
Communication
Different versions of the browser-defined data frame format, Python sent and received in order to deal with the format of packets in order to communicate.
Python receives
Python receives data from the browser and is parsed to get useful data.
Browser package format
Fixed bytes:
(1000 0001 or 1000 0002) It's no use here, ignore
Packet Length bytes:
The first one must be 1, ignore. The remaining 7 bits can get an integer (0 ~ 127), where
(1-125) The byte of the table is a length byte, the size is length;
(126) The next two bytes of the table are the length;
(127) The next eight bytes of the table are the length;
In this way, the length of the data is expressed to save data bits.
Mark Mask:
The mark Mask is 4 bytes after Baochang, and then the sibling data is calculated with the mark mask to get the real data.
Brother Data:
The way to get real data is to do an XOR operation on each x of the sibling data, and the first i%4 bit of the mask, where I is the index of x in the sibling data.
Complete code
def recv_data (self, num):
try:
all_data = self.con.recv (num)
if not Len (all_data): Return
False
Except: return
False
else:
Code_len = Ord (all_data[1]) & 127
If Code_len = 126:
masks = All_ DATA[4:8]
data = all_data[8:]
elif Code_len = = 127:
masks = all_data[10:14]
data = all_data[14:]< C15/>else:
masks = all_data[2:6]
data = all_data[6:]
raw_str = ""
i = 0 for
d in data:
raw_ str = Chr (ord (d) ^ ord (masks[i% 4]))
i = 1 return
raw_str
The WS object of the JS end, which can be sent via Ws.send (str)
Ws.send (str)
Python Send
Python to package data to send, also need to process, send packet format as follows
Fixed byte: Fixed 1000 0001 (' \x81′)
Baochang: Generates 1 or 3 or 9 bytes based on whether the sent data is longer than 0xFFFF (65535), representing the length of the data.
def send_data (self, data):
If data:
data = str (data)
else: return
False
token = "\x81"
length = Len (data)
if length < 126:
token + + struct.pack ("B", length)
elif length <= 0xFFFF:
token + = Struc T.pack ("! BH ", 126, length)
else:
token + + struct.pack ("!) BQ ", 127, length)
#struct为Python中处理二进制数的模块, binary stream is C, or network flow form.
data = '%s%s '% (token, data)
self.con.send (data) return
True
The JS end receives the data via the callback function Ws.onmessage ()
Ws.onmessage = function (result,ntime) {
alert ("Data received from the server:");
Alert ("Last send data to now receive altogether use time:" + ntime);
Console.log (result);
}
Final code
Python Service side
# _*_ coding:utf-8 _*_ __author__ = ' Patrick ' Import socket import Threading import sys import OS import mysqldb Import Base64 Import hashlib Import struct # = = = ' localhost ' PORT = 3368 magic_string = ' 258eafa5-e914-
47da-95ca-c5ab0dc85b11 ' handshake_string = "http/1.1 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" Class Th (threading. Thread): Def __init__ (self, Connection,): Threading. Thread.__init__ (self) Self.con = connection def run (self): while True:try:pass self.con.close () def Recv_data (self, num): Try:all_data = SELF.CON.RECV (num) if not Len (all_data): Return False Except:retur n False else:code_len = ord (all_data[1]) & 127 if Code_len = = 126:masks = All_data[4:8] data = All_d
Ata[8:] elif Code_len = = 127: Masks = all_data[10:14] data = all_data[14:] else:masks = all_data[2:6] data = all_data[6:] Raw_str =
"" i = 0 for D in Data:raw_str + = Chr (ord (d) ^ ord (masks[i% 4])) i + = 1 return raw_str # Send data
def send_data (self, data): If Data:data = str (data) Else:return False token = "\x81" length = Len (data) If length < 126:token + = Struct.pack ("B", length) elif length <= 0xffff:token + = Struct.pack ("! BH ", 126, Length) Else:token + + + struct.pack ("!)
BQ ", 127, length) #struct为Python中处理二进制数的模块, binary stream is C, or network flow form. data = '%s%s '% (token, data) self.con.send (data) return True # handshake def handshake (con): headers = {} s Hake = CON.RECV (1024) if not Len (Shake): Return False header, data = Shake.split (' \r\n\r\n ', 1) to line in H Eader.split (' \ r \ n ') [1:]: Key, val = Line.split (': ', 1) headers[key] = val if ' Sec-websocket-key ' not in headers : Print (' This socket isn't websocket, Client close. ') Con.close () return False Sec_key = headers[' Sec-websocket-key '] Res_key = Base64.b64encode (HASHLIB.SHA1 (Sec_key + magic_string). Digest ()) Str_handshake = Handshake_string.replace (' {1} ', Res_key). Replace (' {2} ', HOST + ': ' + str (PORT )) Print Str_handshake con.send (str_handshake) return True def new_service (): "" "start a service socket and Liste n when coms a connection, start a new thread to handle it "" "Sock = Socket.socket (socket.af_inet, socket. Sock_stream) try:sock.bind ((' localhost ', 3368)) Sock.listen (1000) #链接队列大小 print "Bind 3368,ready to use" except : Print (' Server is already running,quit ') sys.exit () while true:connection, address = Sock.accept () #返回元组 (sock Et,add), accept to the Waite state print "Got connection from" when called, address if Handshake (connection): print "Handshake succes S "try:t = Th (connection, layout) T.start () print ' new thread for client ... ' except:print ' Start New Thread error '
Connection.close () if __name__ = = ' __main__ ': New_service ()
JS Client
<script>
var socket = new WebSocket (' ws://localhost:3368 ');
Ws.onmessage = function (result,ntime) {
alert ("Data received from the server:");
Alert ("Last send data to now receive altogether use time:" + ntime);
Console.log (result);
}
</script>