如何在Python中创buildSocket.io客户端以与Sails服务器通信

我正在运行一个SailsJS实例(v0.12.3),为此,我有一个控制器MyModelController处理一个WebSocket( socket.io )连接,如果用户已经通过authentication,这个连接是允许的。

MyModelController

 module.exports = { /** * Socket connection */ connect: function(req, res) { /* Checks it's a socket connection request */ if (!req.isSocket) { return res.badRequest();} /* Checks it's authenticated */ if (req.session.me) { User.findOne(req.session.me, function (err, me) { if (req.param('name')) { MyModel.findOne({ name: req.param('name') }).exec(function(err, objectFound) { /* eg Join a room named after the params passed */ sails.sockets.join(req, objectFound.name); return res.ok({ message: "All is OK!"}}); }); } }); } } } 

从一个SailsJS服务页面,例如myPage.ejs ,这个效果很好:

 <!DOCTYPE html> <html> <head>...</head> <body> ... <script src="/js/dependencies/sails.io.js"></script> <script src="/js/dependencies/app.io.js"></script> <script src="/vendor/jquery/jquery.min.js"></script> <script type "text/javascript"> // Use .get() to contact the server io.socket.get('/myModel/connect?name=john', function gotResponse(body, response) { console.log('Status code ' + response.statusCode + ' & data: ', body); }); </script> </body> </html> 

如何从Python客户端连接到SailsJS socket.io服务器?

在我的第一次尝试中,我试图稍后离开authentication部分。 所以我们可以说,现在我们不必担心。

我安装了一个Python socket.io客户端pip install socketIO-client-2请参阅socketIO-client-2文档 。

对于初学者来说,尝试这个(哦,顺便说一下,我正在使用自签名证书的安全连接):

 from socketIO_client import SocketIO SocketIO('https://localhost:1337/myModel/connect', params={'name': 'john'}, verify=False) 

但是之后我立即在Sails服务器端得到一个错误:

 verbose: Sending 400 ("Bad Request") response 

在客户端发生错误

 Failed to establish a new connection: [Errno 61] Connection refused 

所以我评论了套接字连接请求和validation检查,使其更简单,希望弄清楚…

 connect: function(req, res) { if (req.param('name')) { MyModel.findOne({ name: req.param('name') }).exec(function(err, objectFound) { console.log(req.socket.id); console.log(param('name')); sails.sockets.join(req, objectFound.name); return res.ok({ message: "All is OK!"}}); }); } else { console.log('No params passed to the websocket'); } } 

这在Sails方面给了我:

 connect > found object: { name: 'john', id: 1, createdAt: '2016-11-04T15:20:38.000Z', updatedAt: '2016-11-04T15:20:38.000Z' } Socket request undefined <============== UNDEFINED warn: Attempted to call `sailsSockets.join`, but the first argument was not a socket. Socket Id: undefined 

我的Python日志:

  /usr/local/lib/python2.7/site-packages/requests/packages/urllib3/connectionpool.py:843: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings InsecureRequestWarning) Traceback (most recent call last): File "wsclient.py", line 17, in <module> SocketIO('https://localhost:1337/myModel/connect', params={'name': 'john'}, verify=False) File "/usr/local/lib/python2.7/site-packages/socketIO_client/__init__.py", line 334, in __init__ resource, hurry_interval_in_seconds, **kw) File "/usr/local/lib/python2.7/site-packages/socketIO_client/__init__.py", line 51, in __init__ self._transport File "/usr/local/lib/python2.7/site-packages/socketIO_client/__init__.py", line 59, in _transport self._engineIO_session = self._get_engineIO_session() File "/usr/local/lib/python2.7/site-packages/socketIO_client/__init__.py", line 73, in _get_engineIO_session transport.recv_packet()) File "/usr/local/lib/python2.7/site-packages/socketIO_client/transports.py", line 81, in recv_packet for engineIO_packet in decode_engineIO_content(response.content): File "/usr/local/lib/python2.7/site-packages/socketIO_client/parsers.py", line 95, in decode_engineIO_content content, content_index) File "/usr/local/lib/python2.7/site-packages/socketIO_client/parsers.py", line 202, in _read_packet_length while get_byte(content, content_index) not in [0, 1]: File "/usr/local/lib/python2.7/site-packages/socketIO_client/symmetries.py", line 28, in get_byte return six.indexbytes(x, index) File "/usr/local/lib/python2.7/site-packages/six.py", line 655, in indexbytes return ord(buf[i]) IndexError: string index out of range 

任何指针?

有趣的链接:

  • 如何连接套接字客户端到Sails-JS服务器 ,但这是使用NodeJS
  • sails.io.js为nodejs

当NodeJS + sails.io.js

我想我想实现这一点,但在Python中

 var socketIOClient = require('socket.io-client'); var sailsIOClient = require('sails.io.js'); // Instantiate the socket client (`io`) // (for now, you must explicitly pass in the socket.io client when using this library from Node.js) var io = sailsIOClient(socketIOClient); // Set some options: // (you have to specify the host and port of the Sails backend when using this library from Node.js) io.sails.url = 'http://localhost:1337'; // ... // Send a GET request to `http://localhost:1337/hello`: io.socket.get('/hello', function serverResponded (body, JWR) { // body === JWR.body console.log('Sails responded with: ', body); console.log('with headers: ', JWR.headers); console.log('and with status code: ', JWR.statusCode); // When you are finished with `io.socket`, or any other sockets you connect manually, // you should make sure and disconnect them, eg: io.socket.disconnect(); // (note that there is no callback argument to the `.disconnect` method) }); 

连接时会给出这个日志

 $ DEBUG=* node sio-client.js socket.io-client:url parse https://localhost:1337 +0ms socket.io-client new io instance for https://localhost:1337 +5ms socket.io-client:manager readyState closed +3ms socket.io-client:manager opening https://localhost:1337 +0ms engine.io-client:socket creating transport "websocket" +1ms engine.io-client:socket setting transport websocket +29ms socket.io-client:manager connect attempt will timeout after 20000 +0ms socket.io-client:manager readyState opening +7ms engine.io-client:socket socket receive: type "open", data "{"sid":"hj4FCwhk_pQ3hoTbAAAE","upgrades":[],"pingInterval":25000,"pingTimeout":60000}" +17ms engine.io-client:socket socket open +0ms socket.io-client:manager open +0ms socket.io-client:manager cleanup +1ms socket.io-client:socket transport is open - connecting +0ms engine.io-client:socket socket receive: type "message", data "0" +215ms socket.io-parser decoded 0 as {"type":0,"nsp":"/"} +0ms socket.io-client:socket emitting packet with ack id 0 +3ms socket.io-client:manager writing packet {"type":2,"data":["get",{"method":"get","headers":{},"data":{},"url":"/mymodel/connect?name=john"}],"options":{"compress":true},"id":0,"nsp":"/"} +0ms socket.io-parser encoding packet {"type":2,"data":["get",{"method":"get","headers":{},"data":{},"url":"/mymodel/connect?name=john"}],"options":{"compress":true},"id":0,"nsp":"/"} +2ms socket.io-parser encoded {"type":2,"data":["get",{"method":"get","headers":{},"data":{},"url":"/mymodel/connect?name=john"}],"options":{"compress":true},"id":0,"nsp":"/"} as 20["get",{"method":"get","headers":{},"data":{},"url":"/mymodel/connect?name=john"}] +0ms engine.io-client:socket flushing 1 packets in socket +1ms |> Now connected to Sails. \___/ For help, see: http: (using sails.io.js node SDK @v1.1.0) engine.io-client:socket socket receive: type "message", data "30[{"body":{"mymodel":{"name":"john","id":1,"createdAt":"2016-11-04T15:20:38.000Z","updatedAt":"2016-11-04T15:20:38.000Z","assembly":"drive"},"message":"DRIVE, Joined room john"},"headers":{"Access-Control-Allow-Origin":"","Access-Control-Allow-Credentials":"","Access-Control-Allow-Methods":"","Access-Control-Allow-Headers":"","Access-Control-Expose-Headers":"","access-control-allow-origin":"","access-control-allow-credentials":"","access-control-allow-methods":"","access-control-allow-headers":"","access-control-expose-headers":""},"statusCode":200}]" +242ms socket.io-parser decoded 30[{"body":{"mymodel":{"name":"john","id":1,"createdAt":"2016-11-04T15:20:38.000Z","updatedAt":"2016-11-04T15:20:38.000Z","assembly":"drive"},"message":"DRIVE, Joined room john"},"headers":{"Access-Control-Allow-Origin":"","Access-Control-Allow-Credentials":"","Access-Control-Allow-Methods":"","Access-Control-Allow-Headers":"","Access-Control-Expose-Headers":"","access-control-allow-origin":"","access-control-allow-credentials":"","access-control-allow-methods":"","access-control-allow-headers":"","access-control-expose-headers":""},"statusCode":200}] as {"type":3,"nsp":"/","id":0,"data":[{"body":{"mymodel":{"name":"john","id":1,"createdAt":"2016-11-04T15:20:38.000Z","updatedAt":"2016-11-04T15:20:38.000Z","assembly":"drive"},"message":"DRIVE, Joined room john"},"headers":{"Access-Control-Allow-Origin":"","Access-Control-Allow-Credentials":"","Access-Control-Allow-Methods":"","Access-Control-Allow-Headers":"","Access-Control-Expose-Headers":"","access-control-allow-origin":"","access-control-allow-credentials":"","access-control-allow-methods":"","access-control-allow-headers":"","access-control-expose-headers":""},"statusCode":200}]} +244ms socket.io-client:socket calling ack 0 with [{"body":{"mymodel":{"name":"john","id":1,"createdAt":"2016-11-04T15:20:38.000Z","updatedAt":"2016-11-04T15:20:38.000Z","assembly":"drive"},"message":"DRIVE, Joined room john"},"headers":{"Access-Control-Allow-Origin":"","Access-Control-Allow-Credentials":"","Access-Control-Allow-Methods":"","Access-Control-Allow-Headers":"","Access-Control-Expose-Headers":"","access-control-allow-origin":"","access-control-allow-credentials":"","access-control-allow-methods":"","access-control-allow-headers":"","access-control-expose-headers":""},"statusCode":200}] +1ms hello again Sails responded with: { mymodel: { name: 'john', id: 1, createdAt: '2016-11-04T15:20:38.000Z', updatedAt: '2016-11-04T15:20:38.000Z', assembly: 'drive' }, message: 'DRIVE, Joined room john' } with headers: { 'Access-Control-Allow-Origin': '', 'Access-Control-Allow-Credentials': '', 'Access-Control-Allow-Methods': '', 'Access-Control-Allow-Headers': '', 'Access-Control-Expose-Headers': '', 'access-control-allow-origin': '', 'access-control-allow-credentials': '', 'access-control-allow-methods': '', 'access-control-allow-headers': '', 'access-control-expose-headers': '' } and with status code: 200 

注意它正在写数据包

  { "type":2, "data":[ "get", { "method":"get", "headers":{}, "data":{}, "url":"/myModel/connect?name=john" } ], "options":{ "compress":true }, "id":0, "nsp":"/" } 

尝试副作用的build议

这里的代码我正在运行pastebin

在风帆边

 verbose: Could not fetch session, since connecting socket has no cookie (is this a cross-origin socket?) Generated a one-time-use cookie:sails.sid=s%3AR-Sm_JeWKoqayZOku-EvxPR_uUpilwVU.3yRUVjmYSpCl%2BeT4sJIOH%2BUTOL3EjWFabDKbswSlkdIand saved it on the socket handshake. This will start this socket off with an empty session, ie (req.session === {}) That "anonymous" section will only last until the socket is disconnected unless you persist the session id in your database, or by setting the set-cookie response header for an HTTP request that you *know* came from the same user (etc) Alternatively, just make sure the socket sends a `cookie` header or query param when it initially connects. 

在socket.io python客户端debugging信息:

 /usr/local/lib/python2.7/dist-packages/requests/packages/urllib3/util/ssl_.py:334: SNIMissingWarning: An HTTPS request has been made, but the SNI (Subject Name Indication) extension to TLS is not available on this platform. This may cause the server to present an incorrect TLS certificate, which can cause validation failures. You can upgrade to a newer version of Python to solve this. For more information, see https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings SNIMissingWarning /usr/local/lib/python2.7/dist-packages/requests/packages/urllib3/util/ssl_.py:132: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. You can upgrade to a newer version of Python to solve this. For more information, see https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings InsecurePlatformWarning /usr/local/lib/python2.7/dist-packages/requests/packages/urllib3/connectionpool.py:843: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings InsecureRequestWarning) DEBUG:root:192.168.178.20:1337/socket.io [transport selected] websocket DEBUG:root:192.168.178.20:1337/socket.io [heartbeat reset] DEBUG:root:192.168.178.20:1337/socket.io [socket.io packet sent] 21["get", {"url": "/path/connect", "headers": {}, "data": {"name": "john"}, "method": "get"}] DEBUG:root:192.168.178.20:1337/socket.io [socket.io packet received] 0 

似乎需要一段时间从您的部分创build一个sails.io.js兼容python包装环绕给定的Socketio库。 所以我想在阅读客户端库的源代码的同时分享实现。

这里的sails.io.js库是这样做的,它通过socketio客户端将.get.post.put函数转换为请求,发送以下数据。

http://localhost:1337初始化socketio客户端库

如下所述传递数据以发挥作为字典的function,

常见的emit数据结构是

 emit_data = { 'method' : 'get', # get, post, delete depends on requirement 'headers' : {'header_key': 'header_value'}, # for passing headers 'data': {'key': 'value'}, # for sending /search/?q=hello, {'q': 'hello'} 'url': '/hello' # } 

如果您需要将最后一个nodejs片段转换为此客户端

 import requests from socketIO_client import SocketIO def server_responded(*body): print 'response', body # first we need to get cookie headers for connection r = requests.get('localhost:1337/__getcookie/') emit_data = { 'method' : 'get', 'url': '/hello', 'headers': {'Cookie': r.headers['Set-Cookie']}, } # update emit_data with extra headers if needed with SocketIO('localhost', 1337) as socketIO: # note: event parameter is request method, here get for GET # second parameter is emit_data structured as described above socketIO.emit(emit_data['method'], emit_data, server_responded) # adjust with your requirements socketIO.wait_for_callbacks(seconds=1) 

我从来没有能够解决我的问题,所以我通过创build一个中继服务器来转发消息从Sails.io连接到socket.io连接,反之亦然。

我使用Flask SocketIO在我的Python模块中创build了一个socket.io服务器,然后让我的中继连接了python服务器(socket.io)和Sails服务器(Sails.io)。

当从SailsJS(Sails.io)收到的消息发送/转发到Python服务器(socket.io)。

在我的示例中, Sails.io客户端首先对Sails进行身份validation,但是我没有为python服务器实现身份validation。

 // Connects to SailsIO on SailsJS instance var sailsIO = require('sails.io.js')(require('socket.io-client')); // Connects to SocketIO server var socketIO = require('socket.io-client')('https://localhost:7000'); socketIO.on('connect', function() { console.log("Connect"); }); socketIO.on('disconnect', function() { console.log("Disconnect"); }); var request = require('request'); var inspect = require('eyespect').inspector({ styles: { all: 'magenta' } }); process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; // Ignore the certs /* Options */ sailsIO.sails.url = 'https://192.168.178.20:1337'; sailsIO.sails.rejectUnauthorized = false; // ... /* Authenticate */ var authJson = { "email": "me@domain.com", "password": "mypassword" }; var options = { method: 'put', body: authJson, json: true, url: 'https://192.168.178.20:1337/login', headers: { 'Content-Type': 'application/json' } } request(options, function(err, res, body) { if (err) { inspect(err, 'error posting json') return } var headers = res.headers var statusCode = res.statusCode var cookie = headers['set-cookie'][0].split(';')[0] inspect(headers, 'headers'); inspect(cookie, "Cookie") inspect(statusCode, 'statusCode'); inspect(body, 'body'); sailsIO.sails.headers = { 'Cookie': cookie }; /* Connects to SailsJS */ sailsIO.socket.request({ method: 'get', url: '/path/to', data: { name: 'john' }, headers: { 'Cookie': cookie } }, function(resData, jwres) { inspect(jwres, "jwres"); if (jwres.error) { console.log(jwres.statusCode); // => eg 403 return; } console.log(jwres.statusCode); // => eg 200 }); }); sailsIO.socket.on('connecting', function() { console.log('Connecting to server'); }); sailsIO.socket.on('hello', function(data) { inspect(JSON.stringify(data), "hello (someone connected)"); }); /** * On message from Sails, re-emit to python SocketIO server via socket.io client */ sailsIO.socket.on('event', function(data) { inspect(JSON.stringify(data), "Data received"); socketIO.emit('event', data); });