如何将 libwebsockets C 客户端连接到 wsrelay 服务器 (node.js)

How to connect a libwebsockets C client to a wsrelay server (node.js)

在我的 mac 上,我安装了 运行 wsrelay

$ wsrelay
listening on port 8124...

在我的 Ubuntu 14.04 上,我编译并 运行 一个简单的 libwebsockets 客户端连接到 wsrelay

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <libwebsockets.h>

#define KGRN "3[0;32;32m"
#define KCYN "3[0;36m"
#define KRED "3[0;32;31m"
#define KYEL "3[1;33m"
#define KBLU "3[0;32;34m"
#define KCYN_L "3[1;36m"
#define KBRN "3[0;33m"
#define RESET "3[0m"

static int destroy_flag = 0;
static int connection_flag = 0;
static int writeable_flag = 0;

static void INT_HANDLER(int signo) {
    destroy_flag = 1;
}

struct session_data {
    int fd;
};

static int websocket_write_back(struct lws *wsi_in, char *str, int str_size_in) 
{
    if (str == NULL || wsi_in == NULL)
        return -1;

    int n;
    int len;
    char *out = NULL;

    if (str_size_in < 1) 
        len = strlen(str);
    else
        len = str_size_in;

    out = (char *)malloc(sizeof(char)*(LWS_SEND_BUFFER_PRE_PADDING + len + LWS_SEND_BUFFER_POST_PADDING));
    //* setup the buffer*/
    memcpy (out + LWS_SEND_BUFFER_PRE_PADDING, str, len );
    //* write out*/
    n = lws_write(wsi_in, out + LWS_SEND_BUFFER_PRE_PADDING, len, LWS_WRITE_TEXT);

    printf(KBLU"[websocket_write_back] %s\n"RESET, str);
    //* free the buffer*/
    free(out);

    return n;
}


static int ws_service_callback(
                         struct lws *wsi,
                         enum lws_callback_reasons reason, void *user,
                         void *in, size_t len)
{

    switch (reason) {

        case LWS_CALLBACK_CLIENT_ESTABLISHED:
            printf(KYEL"[Main Service] Connect with server success.\n"RESET);
            connection_flag = 1;
            websocket_write_back(wsi, "CLT - Client connected to server!", -1);
            break;

        case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
            printf(KRED"[Main Service] Connect with server error.\n"RESET);
            destroy_flag = 1;
            connection_flag = 0;
            break;

        case LWS_CALLBACK_CLOSED:
            printf(KYEL"[Main Service] LWS_CALLBACK_CLOSED\n"RESET);
            destroy_flag = 1;
            connection_flag = 0;
            break;

        case LWS_CALLBACK_CLIENT_RECEIVE:
            printf(KCYN_L"[Main Service] Client received:%s\n"RESET, (char *)in);

            break;
        case LWS_CALLBACK_CLIENT_WRITEABLE :
            printf(KYEL"[Main Service] On writeable is called. send byebye message\n"RESET);
            websocket_write_back(wsi, "Byebye! See you later", -1);
            writeable_flag = 1;
            break;

        default:
            break;
    }

    return 0;
}


int main(void)
{
    //* register the signal SIGINT handler */
    struct sigaction act;
    act.sa_handler = INT_HANDLER;
    act.sa_flags = 0;
    sigemptyset(&act.sa_mask);
    sigaction( SIGINT, &act, 0);

    struct lws_context *context = NULL;
    struct lws_context_creation_info info;
    struct lws *wsi = NULL;
    struct lws_protocols protocol;

    memset(&info, 0, sizeof info);
    info.port = CONTEXT_PORT_NO_LISTEN;
    info.iface = NULL;
    info.protocols = &protocol;
    info.ssl_cert_filepath = NULL;
    info.ssl_private_key_filepath = NULL;
    info.extensions = lws_get_internal_extensions();
    info.gid = -1;
    info.uid = -1;
    info.options = 0;

    protocol.name  = "my-echo-protocol";
    protocol.callback = &ws_service_callback;
    protocol.per_session_data_size = sizeof(struct session_data);
    protocol.rx_buffer_size = 0;
    protocol.id = 0;
    protocol.user = NULL;

    context = lws_create_context(&info);
    printf(KRED"[Main] context created.\n"RESET);

    if (context == NULL) {
        printf(KRED"[Main] context is NULL.\n"RESET);
        return -1;
    }

    wsi = lws_client_connect(context, "Mac-IP-address", 8124, 0,
            "/", "Mac-IP-address:8124", NULL,
             protocol.name, -1);
    if (wsi == NULL) {
        printf(KRED"[Main] wsi create error.\n"RESET);
        return -1;
    }

    printf(KGRN"[Main] wsi create success.\n"RESET);

    while(!destroy_flag)
    {
        lws_service(context, 50);
    }

    lws_context_destroy(context);

    return 0;
}

但是当我 运行 客户端时,使用 websocket_write_back 发送到服务器的消息从未到达服务器,尽管连接似乎已正确建立。我猜这是关于协议的事情??关于我可能做错了什么的任何指示?

$ ./example-client 
[1452543414:0970] NOTICE: Initial logging level 7
[1452543414:0971] NOTICE: Libwebsockets version: 1.6.0 0c7e5a9
[1452543414:0971] NOTICE: IPV6 not compiled in
[1452543414:0971] NOTICE: libev support not compiled in
[1452543414:0972] NOTICE:  mem: platform fd map:  8192 bytes
[1452543414:0972] NOTICE:  mem: per-conn:          352 bytes + protocol rx buf
[1452543414:0972] NOTICE:  canonical_hostname = linux-Lenovo-G50-70
[Main] context created.
[Main] wsi create success.
[Main Service] Connect with server success.
[websocket_write_back] CLT - Client connected to server!

不确定您在此期间是否设法解决了它。这是我的猜测:您的代码很好,wsrelay.

有问题

我已经 运行 你的代码(gcc 抱怨一些打字,我会在这个答案的底部附加差异)并且一切似乎都工作正常。但是 wsrelay 没有像你说的那样报告任何东西,这是可疑的,所以我创建了不同的 ws 服务器。基本上相同的功能(我想,从来没有真正看到 wsrelay 工作......) - 它记录客户端连接,打印发送的消息并记录客户端断开连接。

此服务器能够捕获您的消息。所以我鼓励你删除 wsrelay 并使用下面的服务器代码作为你的基础。它是我找到的代码的精简版 here。希望这有帮助。

WS 服务器源

var webSocketsServerPort = 8124;

var webSocketServer = require('websocket').server;
var http = require('http');

var server = http.createServer(function(request, response) {});
server.listen(webSocketsServerPort, function() {
    console.log((new Date()) + " Server is listening on port " + webSocketsServerPort);
});
var wsServer = new webSocketServer({httpServer: server});

wsServer.on('request', function(request) {
    console.log((new Date()), 'New connection.');
    var connection = request.accept();

    connection.on('message', function(message) {
        console.log(message.utf8Data);
    });

    connection.on('close', function(connection) {
        console.log((new Date()), 'Connection closed.');
    });
});

WS 服务器输出

$ node server.js 
Sun Feb 14 2016 13:57:43 GMT+0100 (CET) Server is listening on port 8124
Sun Feb 14 2016 13:57:44 GMT+0100 (CET) 'New connection.'
CLT - Client connected to server!
Byebye! See you later
Byebye! See you later
Sun Feb 14 2016 13:58:31 GMT+0100 (CET) 'Connection closed.'

您的 C 客户端输出(来自 gdb)

$ gdb stack
...
(gdb) run
Starting program: /tmp/stack 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
[1455454664:6989] NOTICE: Initial logging level 7
[1455454664:6989] NOTICE: Libwebsockets version: 1.6.0 unknown-build-hash
[1455454664:6989] NOTICE: IPV6 not compiled in
[1455454664:6989] NOTICE: libev support not compiled in
[1455454664:6989] NOTICE:  ctx mem: 21088 bytes
[1455454664:6990] NOTICE:  canonical_hostname = gentee
[1455454664:6990] NOTICE:  per-conn mem: 256 + 2126 headers + protocol rx buf
[Main] context created.
[Main] wsi create success.
[Main Service] Connect with server success.
[websocket_write_back] CLT - Client connected to server!
[Main Service] On writeable is called. send byebye message
[websocket_write_back] Byebye! See you later
[Main Service] On writeable is called. send byebye message
[websocket_write_back] Byebye! See you later
^C

差异(为了 运行 你的客户我必须做的修改)

$ diff --unchanged-line-format="" --old-line-format="" --new-line-format="%dn: %L" /tmp/stack.*
36:     unsigned char *out = NULL;
43:     out = (unsigned char *)malloc(sizeof(unsigned char)*(LWS_SEND_BUFFER_PRE_PADDING + len + LWS_SEND_BUFFER_POST_PADDING));
68:             websocket_write_back(wsi, (char *)"CLT - Client connected to server!", -1);
89:             websocket_write_back(wsi, (char *)"Byebye! See you later", -1);
141:     wsi = lws_client_connect(context, "localhost", 8124, 0,
142:             "/", "localhost:8124", NULL,