libwebsockets записывают все активные соединения после получения

Я играю с учебным пособием по libwebsockets, пытаясь сделать так, чтобы после получения сообщения от соединения по заданному протоколу он отправлял ответ всем активным соединениям, реализующим этот протокол. Я использовал функцию libwebsocket_callback_all_protocol, но она не делает того, что, как я думаю, должна делать, судя по ее названию (я не совсем уверен, что она делает из документации).

Цель состоит в том, чтобы открыть две веб-страницы, и, когда информация отправляется с одной, результат будет передан на обе. Ниже мой код - вы увидите, что libwebsocket_callback_all_protocol вызывается в main (который, я думаю, в настоящее время ничего не делает....):

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

static int callback_http(struct libwebsocket_context * this,
                         struct libwebsocket *wsi,
                         enum libwebsocket_callback_reasons reason, void *user,
                         void *in, size_t len)
{
    return 0;
}

static int callback_dumb_increment(struct libwebsocket_context * this,
                                   struct libwebsocket *wsi,
                                   enum libwebsocket_callback_reasons reason,
                                   void *user, void *in, size_t len)
{

    switch (reason) {
        case LWS_CALLBACK_ESTABLISHED: // just log message that someone is connecting
            printf("connection established\n");
            break;
        case LWS_CALLBACK_RECEIVE: { // the funny part
            // create a buffer to hold our response
            // it has to have some pre and post padding. You don't need to care
            // what comes there, libwebsockets will do everything for you. For more info see
            // http://git.warmcat.com/cgi-bin/cgit/libwebsockets/tree/lib/libwebsockets.h#n597
            unsigned char *buf = (unsigned char*) malloc(LWS_SEND_BUFFER_PRE_PADDING + len +
                                                         LWS_SEND_BUFFER_POST_PADDING);

            int i;

            // pointer to `void *in` holds the incomming request
            // we're just going to put it in reverse order and put it in `buf` with
            // correct offset. `len` holds length of the request.
            for (i=0; i < len; i++) {
                buf[LWS_SEND_BUFFER_PRE_PADDING + (len - 1) - i ] = ((char *) in)[i];
            }

            // log what we recieved and what we're going to send as a response.
            // that disco syntax `%.*s` is used to print just a part of our buffer
            // http://stackoverflow.com/questions/5189071/print-part-of-char-array
            printf("received data: %s, replying: %.*s\n", (char *) in, (int) len,
                 buf + LWS_SEND_BUFFER_PRE_PADDING);

            // send response
            // just notice that we have to tell where exactly our response starts. That's
            // why there's `buf[LWS_SEND_BUFFER_PRE_PADDING]` and how long it is.
            // we know that our response has the same length as request because
            // it's the same message in reverse order.
            libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], len, LWS_WRITE_TEXT);

            // release memory back into the wild
            free(buf);
            break;
        }
        default:
            break;
    }


    return 0;
}

static struct libwebsocket_protocols protocols[] = {
    /* first protocol must always be HTTP handler */
    {
        "http-only",   // name
        callback_http, // callback
        0,              // per_session_data_size
        0
    },
    {
        "dumb-increment-protocol", // protocol name - very important!
        callback_dumb_increment,   // callback
        0,                          // we don't use any per session data
        0

    },
    {
        NULL, NULL, 0, 0   /* End of list */
    }
};

int main(void) {
    // server url will be http://localhost:9000
    int port = 9000;
    const char *interface = NULL;
    struct libwebsocket_context *context;
    // we're not using ssl
    const char *cert_path = NULL;
    const char *key_path = NULL;
    // no special options
    int opts = 0;

    // create libwebsocket context representing this server
    struct lws_context_creation_info info;
    memset(&info, 0, sizeof info);   

    info.port = port;
    info.iface = interface;
    info.protocols = protocols;
    info.extensions = libwebsocket_get_internal_extensions();
    info.ssl_cert_filepath = cert_path;
    info.ssl_private_key_filepath = key_path;
    info.gid = -1;
    info.uid = -1;
    info.options = opts;
    info.user = NULL;
    info.ka_time = 0;
    info.ka_probes = 0;
    info.ka_interval = 0;

    /*context = libwebsocket_create_context(port, interface, protocols,
                                          libwebsocket_get_internal_extensions,
                                          cert_path, key_path, -1, -1, opts);
   */
    context = libwebsocket_create_context(&info);
    if (context == NULL) {
        fprintf(stderr, "libwebsocket init failed\n");
        return -1;
    }

    libwebsocket_callback_all_protocol(&protocols[1], LWS_CALLBACK_RECEIVE);

    printf("starting server...\n");

    // infinite loop, to end this server send SIGTERM. (CTRL+C)
    while (1) {
        libwebsocket_service(context, 50);
        // libwebsocket_service will process all waiting events with their
        // callback functions and then wait 50 ms.
        // (this is a single threaded webserver and this will keep our server
        // from generating load while there are not requests to process)
    }

    libwebsocket_context_destroy(context);

    return 0;
}

person mikesol    schedule 16.08.2014    source источник


Ответы (2)


У меня была та же проблема: libwebsocket_write на LWS_CALLBACK_ESTABLISHED генерировал случайный segfault, поэтому, используя список рассылки, разработчик libwebsockets Энди Грин проинструктировал меня, что правильный способ - использовать libwebsocket_callback_on_writable_all_protocol, файл test-server/test-server.c в исходном коде библиотеки показывает пример использования.

libwebsocket_callback_on_writable_all_protocol(libwebsockets_get_protocol(wsi))

Он работал очень хорошо, чтобы уведомить все экземпляры, но он вызывает только метод записи во всех подключенных экземплярах, он не определяет данные для отправки. Вы должны управлять данными самостоятельно. Пример исходного файла test-server.c показывает пример кольцевого буфера для этого.

http://ml.libwebsockets.org/pipermail/libwebsockets/2015-January/001580.html

Надеюсь, поможет.

person ton    schedule 26.01.2015
comment
Спасибо за подсказку! Удалось ли вам написать код, который отправляет данные во все экземпляры? - person VisioN; 14.03.2015
comment
Да, работает как шарм... как сказано, посмотрите на test-server.c в исходном коде libwebsocket git, чтобы увидеть рабочий код. git.libwebsockets.org/cgi- bin/cgit/libwebsockets/дерево/ - person ton; 15.03.2015

Из того, что я могу быстро взять из документации, чтобы отправить сообщение всем клиентам, вам нужно где-то сохранить (в векторе, хэш-карте, массиве, что угодно) struct libwebsocket * wsi, к которому у вас есть доступ, когда ваши клиенты подключаются .

Затем, когда вы получите сообщение и захотите его передать, просто вызовите libwebsocket_write на всех экземплярах wsi *.

Во всяком случае, это то, что я бы сделал.

person nschoe    schedule 02.09.2014