Python communication sample analysis via WebSocket and JS client

Source: Internet
Author: User
Tags ord sha1
Specific WebSocket introduction Visible Http://zh.wikipedia.org/wiki/WebSocket

Here, we describe how to use Python to communicate with the front-end JS.

WebSocket after the handshake is completed using the HTTP protocol, WebSocket communication is not made directly through HTTP.

So, use WebSocket roughly two steps: Use HTTP handshake, communication.

JS processing websocket to use the WS module, Python processing uses the socket module to establish a TCP connection, more than the average 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.1host:server.example.comupgrade:websocketconnection:upgradesec-websocket-key: Dghlihnhbxbszsbub25jzq==origin:http://example.comsec-websocket-protocol:chat, Superchatsec-websocket-version:13

Server Response Package Format:

http/1.1 101 Switching protocolsupgrade:websocketconnection:upgradesec-websocket-accept:s3pplmbitxaq9kygzzhzrbk+ Xoo=sec-websocket-protocol:chat

Where 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 has a class to handle the WebSocket, after the initialization of the auto-send handshake package, as follows:

var socket = new WebSocket (' ws://localhost:3368 ');

Python side

Python accepts the handshake string with the socket, sends it after processing

HOST = ' localhost ' PORT = 3368magic_string = ' 258eafa5-e914-47da-95ca-c5ab0dc85b11 ' handshake_string = ' http/1.1 101 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 "def handshake (Con): #con为用soc Ket,accept () get the socket# here omitted to listen, accept the code, specifically visible blog:http://blog.csdn.net/ice110956/article/details/29830627 headers = {} shake = Con.recv (1024x768) if not Len (Shake): Return to False header, data = Shake.split (' \r\n\r\n ', 1) for line in Heade R.split (' \ r \ n ') [1:]: Key, val = Line.split (': ', 1) headers[key] = val if ' Sec-websocket-key ' not in Headers:print ('  This socket was not 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 

Communication

Different versions of browser-defined data frame formats are different, and Python sends and receives data packets to be processed in a format to communicate.

Python Receive

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 useless here, ignoring

Packet length byte:

The first bit must be 1, ignore. The remaining 7 bits can be given an integer (0 ~ 127), where

(1-125) Table This byte is the length byte, the size is the length;

(126) The next two bytes of the table is the length;

(127) The next eight bytes of the table is the length;

In this way, the length of the data is expressed and the data bits are saved.

Mark Mask:

The mark Mask is 4 bytes after Kanenaga, and then the sibling data is calculated with the mark mask to get real data.

Brother Data:

The way to get real data: To do an XOR operation for each digit x of the sibling data, and the i%4 bit of the mask, where I is the index of x in the sibling data.

Full 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]   D ATA = all_data[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

The WS object on the JS side, which can be sent via Ws.send (str)

Ws.send (str)

Python Send

Python to packet data sent, also need to process, send packet format as follows

Fixed byte: fixed 0001 (' \x81′)

Kanenaga: Depending on whether the sent data length exceeds 0xFFFF (65535) to generate 1 or 3 or 9 bytes, to represent the length of a data.

def send_data (self, data): If data:  data = str (data) Else:  return False token = "\x81" length = Len (data) if Lengt H < 126:  token + = Struct.pack ("B", length) elif length <= 0xFFFF:  token + = Struct.pack ("! BH ", 126, length) Else:  token + = Struct.pack ("! BQ ", 127, length) #struct为Python中处理二进制数的模块, the binary stream is C, or the form of a network stream. data = '%s%s '% (token, data) self.con.send (data) return True

JS end accepts data via callback function Ws.onmessage ()

Ws.onmessage = function (result,ntime) {alert ("Data received from the server:"), alert ("Last send data to now receive total usage time:" + ntime); Console.log (Result );}

Final code

Python Service side

# _*_ Coding:utf-8 _*___author__ = ' Patrick ' import socketimport threadingimport sysimport osimport mysqldbimport base64im Port hashlibimport struct # ====== config ======host = ' localhost ' port = 3368magic_string = ' 258eafa5-e914-47da-95ca-c5ab0 Dc85b11 ' handshake_string = "http/1.1 101 switching protocols\r\n" \ "upgrade:websocket\r\n" \ "Connection:upgra de\r\n "\" sec-websocket-accept: {1}\r\n "\" websocket-location:ws://{2}/chat\r\n "\" Websocket-protocol:c Hat\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: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:]   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中处理二进制数的模块, the binary stream is C, or the form of a network stream. data = '%s%s '% (token, data) self.con.send (data) return True # handshake def handshake (con): headers = {} shake = C ON.RECV (1024x768) if not Len (Shake): Return to False header, data = Shake.split (' \r\n\r\n ', 1) for line in Header.split (' \ r\n ') [1:]: Key, val = Line.split (': ', 1) headers[key] = val if ' Sec-websocket-key ' not in Headers:print (' this s   Ocket is not 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 listen 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 (+) #链接队列大小 print "Bind 3368,ready to use" Except:pri NT ("Server is already Running,quit") Sys.exit () while true:connection, address = Sock.accept () #返回元组 (Socket,add), ACCE PT calls will enter Waite status print "Got connection from", address if Handshake (connection): print "handshake success" 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

  • Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.