我无法从本机 C++ WebSocket (www.websocket.org) 客户端与 socket.io 服务器交换数据。请注意,我不想要基于 Boost 的解决方案,因为我正在从嵌入式系统运行 WebSocket 客户端(它必须是轻量级的)。
我已经尝试过 LWS_WRITE_TEXT 和 LWS_WRITE_HTTP(无填充)模式。我没有使用安全套接字(即,不使用 wss 或 SSL 证书)。
myServer.js:
var io = require('socket.io').listen(80);
io.configure('production', function(){
io.enable('browser client etag');
io.set('log level', 3);
io.set('transports', ['websocket']);
});
io.configure('development', function(){
io.set('log level', 3);
io.set('transports', ['websocket']);
});
io.sockets.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
我已经增强了 libwebsockets-test-echo.cpp 示例代码作为起点,并且当客户端和服务器都使用 WebSockets C++ API 时它可以正常工作。但是,当我连接到 socket.io 服务器时,服务器控制台会报告: warn - unknown transport: "undefined" 。
客户端.cpp:
...
struct per_session_data__echo {
// for LWS_WRITE_TEXT mode, PRE_PADDING is defined to LWS_SEND_BUFFER_PRE_PADDING and POST_PADDING is LWS_SEND_BUFFER_POST_PADDING, otherwise they're both set to 0.
unsigned char buf[PRE_PADDING + 1400 + POST_PADDING];
unsigned int len;
unsigned int index;
};
static int callback_echo(struct libwebsocket_context *context,
struct libwebsocket *wsi,
enum libwebsocket_callback_reasons reason, void *user,
void *in, size_t len)
{
struct per_session_data__echo *pss = (struct per_session_data__echo *)user;
int n;
switch (reason) {
case LWS_CALLBACK_CLIENT_ESTABLISHED:
lwsl_notice("Client has connected\n");
pss->index = 0;
break;
case LWS_CALLBACK_CLIENT_RECEIVE:
lwsl_notice("Client RX: %s", (char *)in);
break;
case LWS_CALLBACK_CLIENT_WRITEABLE:
/* we will send our packet... */
pss->len = sprintf((char *)&pss->buf[LWS_SEND_BUFFER_PRE_PADDING], "hello from libwebsockets-test-echo client pid %d index %d\n", getpid(), pss->index++);
lwsl_notice("Client TX: %s", &pss->buf[LWS_SEND_BUFFER_PRE_PADDING]);
n = libwebsocket_write(wsi, &pss->buf[LWS_SEND_BUFFER_PRE_PADDING], pss->len, LWS_WRITE_TEXT);
if (n < 0) {
lwsl_err("ERROR %d writing to socket, hanging up\n", n);
return -1;
}
if (n < (int)pss->len) {
lwsl_err("Partial write\n");
return -1;
}
break;
default:
break;
}
return 0;
}
static struct libwebsocket_protocols protocols[] = {
/* first protocol must always be HTTP handler */
{
"my other event", /* name */
callback_echo, /* callback */
sizeof(struct per_session_data__echo), /* per_session_data_size */
0
},
{
NULL, NULL, 0, 0 /* End of list */
}
};
...
struct lws_context_creation_info info;
info.port = CONTEXT_PORT_NO_LISTEN;
info.iface = "eth0";
info.gid = -1;
info.uid = -1;
info.options = 0;
info.extensions = libwebsocket_get_internal_extensions();
info.protocols = protocols;
libwebsocket_context context_;
context_ = libwebsocket_create_context(&info);
libwebsocket *wsi_;
wsi_ = libwebsocket_client_connect(context_,
"localhost",
80, // port
0, // "ws:" (no SSL)
"/socket.io", // path
"localhost", // host name
"controller", // Socket origin name
"my other event", // libwebsocket protocol name
-1
);
...
libwebsocket_callback_on_writable_all_protocol(&protocols_[0]);
...
int rc = 0;
unsigned int oldus = 0;
while (rc >= 0 && !forceExit_) {
struct timeval tv;
gettimeofday(&tv, NULL);
if (((unsigned int)tv.tv_usec - oldus) > pollingRate_) {
oldus = tv.tv_usec;
}
rc = libwebsocket_service(context_, 1000); // wait 1000 msec
if (rc != 0) printf("rc=%d\n", rc);
}
...
这是“sudo node server.js”的输出:
info - socket.io started
warn - unknown transport: "undefined"
这是 client.cpp 控制台的输出。不要被“listening on port=0”误导,因为它是 libwebsockets-test-echo.cpp 使用的上下文端口设置,它适用于 websocket 到 websocket 客户端和服务器。请注意,连接完成,对于 LWS_WRITE_TEXT 和 LWS_WRITE_HTTP 模式,此输出相同。
listening on port=0
listening on interface=eth0
lwsts[12960]: Initial logging level 7
lwsts[12960]: Library version: 1.3 502b994
lwsts[12960]: Started with daemon pid 0
lwsts[12960]: static allocation: 4488 + (16 x 1024 fds) = 20872 bytes
lwsts[12960]: canonical_hostname = sogo
lwsts[12960]: context->protocols[0].name='my other event'
lwsts[12960]: LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS
lwsts[12960]: context->protocols[0].name='my other event'
lwsts[12960]: LWS_CALLBACK_PROTOCOL_INIT
lwsts[12960]: WebSocketClient::connect(): connecting to localhost:80 ...
sslCerts=0
protocolNameList='my other event'
connecting to address=localhost and port=80
lwsts[13340]: context->protocols[0].name='my other event'
lwsts[13340]: LWS_CALLBACK_ADD_POLL_FD
lwsts[13340]: context->protocols[0].name='my other event'
lwsts[13340]: LWS_CALLBACK_CLEAR_MODE_POLL_FD
lwsts[13340]: context->protocols[0].name='my other event'
lwsts[13340]: LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED
lwsts[13340]: context->protocols[0].name='my other event'
lwsts[13340]: LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER
lwsts[13340]: WebSocketClient::connect(): connected to localhost:80
lwsts[13340]: context->protocols[0].name='my other event'
lwsts[13340]: LWS_CALLBACK_SET_MODE_POLL_FD
lwsts[13340]: WebSocketClient::run(): running ...
lwsts[13340]: problems parsing header
lwsts[13340]: context->protocols[0].name='my other event'
lwsts[13340]: LWS_CALLBACK_DEL_POLL_FD