0x00 前言
Socket,一种开销很小的实现程序之间通信的方式。不同的编程语言几乎都有自己实现Socket的库和方法,建立在Socket基础上的许多通信协议也都广泛运用于各种框架中,之前在博客分享的Hpfeeds协议实际上就是建立在Socket的基础上。
不同编程语言之间也经常使用Socket来传递消息,这样可以避免不同语言之间的嵌套调用。如题,这里我们需要在Python和Js之间实现一个消息传递。
0x01 实现
最初查找资料的时候,许多博客中都提到了说,Js本身是不能够实现Socket的,而常用的方法实际上是利用Flash的Socket来进行通信,然后通过Js获得Flash的响应事件来传递数据。为此有一个专门的Js库叫Aflax。
同时,另一种更新的方法是使用Html5协议中的WebSocket来实现浏览器和服务器的通信。
关于WebSocket的具体协议就不在这里详述了,毕竟我也没有认真去看。
实现WebSocket通信的方法也有很多种,网上容易查到的是使用Node.js的实现方法https://github.com/SushisMakis/WebSocket
这里,作者提供个一个Python实现的服务器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
import struct import SocketServerfrom base64 import b64encode, b64decodefrom hashlib import sha1from mimetools import Messagefrom StringIO import StringIO clients = []; class WebSocketsHandler (SocketServer.StreamRequestHandler) : magic = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11' def setup (self) : SocketServer.StreamRequestHandler.setup(self) print "connection established" , self.client_address self.handshake_done = False def handle (self) : while True : if not self.handshake_done: self.handshake() clients.append(self) else : try : self.read_next_message () except : self.request.close() return def read_next_message (self) : length = ord(self.rfile.read(2 )[1 ]) & 127 if length == 126 : length = struct .unpack(">H" , self.rfile.read(2 ))[0 ] elif length == 127 : length = struct.unpack(">Q" , self.rfile.read(8 ))[0 ] masks = [ord(byte) for byte in self.rfile.read(4 )] decoded = "" for char in self.rfile.read(length): decoded += chr(ord(char) ^ masks[len(decoded) % 4 ]) self.on_message(decoded) def send_message (self, data , fin=True, opcode=1 , masking_key=False) : header = struct.pack('!B' , ((fin << 7 ) | (0 << 6 )| (0 << 5 )| (0 << 4 )| opcode)) if masking_key: mask_bit = 1 << 7 else : mask_bit = 0 length = len(data) if length < 126 : header += struct.pack('!B' , (mask_bit | length)) elif length < (1 << 16 ): header += struct.pack('!B' , (mask_bit | 126 )) + struct.pack('!H' , length) elif length < (1 << 63 ): header += struct.pack('!B' , (mask_bit | 127 )) + struct.pack('!Q' , length) body = data self.request.send(bytes(header + body)) def handshake (self) : data = self.request.recv(1024 ).strip() headers = Message(StringIO(data.split('\r\n' , 1 )[1 ])) if headers.get("Upgrade" , None ) != "websocket" : return print 'Handshaking...' key = headers['Sec-WebSocket-Key' ] digest = b64encode(sha1(key + self.magic).hexdigest().decode('hex' )) response = 'HTTP/1.1 101 Switching Protocols\r\n' +'Upgrade: websocket\r\n' +'Connection: Upgrade\r\n' response += 'Sec-WebSocket-Accept: %s\r\n\r\n' % digest self.handshake_done = self.request.send(response) def on_message (self, message) : text = b64decode(message) print text for client in clients: if client.client_address != self.client_address: client.send_message(b64encode(text)) class ThreadedTCPServer (SocketServer.ThreadingMixIn, SocketServer.TCPServer) : pass if __name__ == "__main__" : server = ThreadedTCPServer(("localhost" , 9999 ), WebSocketsHandler) server.serve_forever()
我们使用其中的这段代码作为服务器。
用这段Js作为浏览器端的接收Demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
var smWs = new SmWebSocket("localhost" ,9999 ,true ,handle_recv);smWs.open(); var myDictObjectProtocol = {"p1top2" : handle_transit}; var p = new Protocol(myDictObjectProtocol,"|" ); function handle_recv (event ) { var data = event.data; data = Base64.decode(data); alert(data); p.handleMessage(data); } function handle_transit (mess ) { document .getElementById("data_in" ).innerText = mess; }
这里作者只实现了浏览器发送到服务器以及浏览器之间的交互,所以现在我们还缺一个Python发送的程序,我最初希望直接使用Pyhton的Socket来实现一个端口发送,但是最后发现每次发送的程序都被服务器拒绝了,所以我又找到了一个Python实现的WebSocket库,当然这个和Pip下载的WebSocket库不同。
https://github.com/liris/websocket-client
我修改了其中编码的部分,以和之前的程序适应
1 2 3 4 5 6 7 8 9 10 11
from __future__ import print_function import websocket import base64 if __name__ == "__main__" : #websocket .enableTrace (True) ws = websocket.create_connection ("ws://localhost:9999" ) data = "p1top2|Hello World" data = base64.b64encode (data) ws.send (data) ws.close ()
要求的库直接Clone上面项目里的即可,这样,我们就实现了通过Python和Js进行Socket通信的程序。
FROM : phantom0301 | Author:phantom0301
评论