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

zab*_*mba 8 python node.js socket.io sails.js

我正在运行一个SailsJS实例(v0.12.3),我有一个控制器MyModelController处理WebSocket(socket.io)连接,如果用户已经过身份验证,则允许该连接.

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) {

              /* e.g. Join a room named after the params passed */
              sails.sockets.join(req, objectFound.name); 

              return res.ok({ message: "All is OK!"}});
            });
          } 
        });
      }
    }
}
Run Code Online (Sandbox Code Playgroud)

从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>
Run Code Online (Sandbox Code Playgroud)

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

在我的几次尝试中,我尝试将身份验证部分留待以后使用.所以,让我们说,我们现在不必担心它.

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

并且对于初学者尝试了这个(哦和BTW我使用自签名证书的安全连接):

from socketIO_client import SocketIO

SocketIO('https://localhost:1337/myModel/connect', params={'name': 'john'}, verify=False)
Run Code Online (Sandbox Code Playgroud)

但后来我在Sails服务器端立即收到错误:

verbose: Sending 400 ("Bad Request") response
Run Code Online (Sandbox Code Playgroud)

在客户端有错误

Failed to establish a new connection: [Errno 61] Connection refused
Run Code Online (Sandbox Code Playgroud)

所以我注释掉套接字连接请求和经过身份验证的检查,以使其更简单,希望能够弄清楚...

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');
  }
}
Run Code Online (Sandbox Code Playgroud)

这让我在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
Run Code Online (Sandbox Code Playgroud)

我的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
Run Code Online (Sandbox Code Playgroud)

有什么指针吗?

有趣的链接:

当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, e.g.:
  io.socket.disconnect();

  // (note that there is no callback argument to the `.disconnect` method)
});
Run Code Online (Sandbox Code Playgroud)

在连接时给出这个日志

$ 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
Run Code Online (Sandbox Code Playgroud)

请注意它正在写包

 {  
   "type":2,
   "data":[  
      "get",
      {  
         "method":"get",
         "headers":{},
         "data":{},
         "url":"/myModel/connect?name=john"
      }
   ],
   "options":{  
      "compress":true
   },
   "id":0,
   "nsp":"/"
}
Run Code Online (Sandbox Code Playgroud)

尝试副作用的建议

这里的代码我正在运行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, i.e. (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.
Run Code Online (Sandbox Code Playgroud)

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

/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
Run Code Online (Sandbox Code Playgroud)

Ren*_*han 5

似乎您需要一些时间来围绕给定的 Socketio 库创建一个与 Sails.io.js 兼容的 Python 包装器。所以我想在阅读客户端库的源代码时分享实现。

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

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

传递数据以emit用作字典,如下所述,

常见的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' # 
}
Run Code Online (Sandbox Code Playgroud)

如果您需要将最后转换的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)
Run Code Online (Sandbox Code Playgroud)