Python through WebSocket and JS client communication example Analysis _python

Source: Internet
Author: User
Tags base64 ord pack sha1 in python

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>

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.