簡體   English   中英

如何在Python中創建Socket.io客戶端以與Sails服務器對話

[英]How to create Socket.io client in Python to talk to a Sails server

我正在運行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!"}});
            });
          } 
        });
      }
    }
}

從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服務器?

在最初的幾次嘗試中,我嘗試將身份驗證部分留給以后使用。 可以這么說,我們現在不必擔心。

我安裝了Python socket.io客戶端pip install socketIO-client-2請參見socketIO-client-2 doc

對於初學者來說,這樣做(哦,順便說一句,我正在使用帶有自簽名證書的安全連接):

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

所以我注釋掉了套接字連接請求和經過身份驗證的檢查,以使其變得更簡單,希望能找出來...

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');
  }
}

這使我站在帆邊:

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

有指針嗎?

有趣的鏈接:

當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)
});

連接時給出此日志

$ 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":"/"
}

嘗試副作用的建議

這是我正在運行的代碼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.

在socket.io python客戶端上的調試信息:

/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

似乎需要花費一些時間來創建一個sails.io.js兼容性python包裝器,該包裝器圍繞給定的Socketio庫。 因此,我認為在閱讀客戶端庫的源代碼時共享實現。

此處的sails.io.js庫執行此操作,它將通過發送以下數據的socketio客戶端將.get.post.put函數轉換為請求。

使用http://localhost:1337初始化socketio客戶端庫

傳遞數據以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' # 
}

如果您需要將最后一個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)

我一直無法解決我的問題,因此我通過創建中繼服務器來解決此問題,該服務器將消息從Sails.io連接轉發到socket.io連接,反之亦然。

我使用Flask SocketIO在Python模塊中創建了一個socket.io服務器,然后讓我的中繼連接python服務器(socket.io)和Sails服務器(Sails.io)。

當從SailsJS(Sails.io)收到消息后,將其發送/轉發到python服務器(socket.io)。

在我的示例中, Sails.io客戶端首先向Sails進行身份驗證,但是我尚未為python服務器實現身份驗證。

// 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); // => e.g. 403
            return;
        }
        console.log(jwres.statusCode); // => e.g. 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);
});

您需要在網址中添加__sails_io_sdk_version=0.11.0 ,如下所示:

var socketIO = require('socket.io-client')('https://localhost:7000/?__sails_io_sdk_version=0.11.0'');

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM