如何在Python中创建Socket.io客户端以与Sails服务器对话
问题描述
我正在运行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
有什么指示吗?
有趣链接:
- how-to-connect-socket-io-client-to-sails-js-server,但使用的是NodeJS
- sails.io.js for 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, 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
解决方案
似乎需要一段时间才能围绕给定的Socketio库创建一个sails.io.js兼容性Python包装器。所以我想在阅读客户端库源代码的同时共享实现。
这里的sails.io.js
库的作用是将.get
、.post
、.put
函数转换为通过Socketio客户端发送以下数据的请求。
使用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代码段转换为thisclientAS
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)
相关文章