Page 1 of 1

libwebsockets异常断连(LWS_CALLBACK_CLIENT_CLOSED)

Posted: 2025-01-14 15:34
by XUESI LI
用arm-rockchip交叉编译工具链把一个libwebsockets的客户端程序编译到RV1106上,程序运行会自动断连。而完全相同的代码,gcc编译为X86可执行程序则运行完全正常。
程序代码如下:

Code: Select all

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

static struct lws *wsi = NULL;
static int established = 0;
static int isBreak = 0;
static int stop = 0;

int UnmarshalURL(const char *_url, char *_protocol, char *_host, int *_port, char *path)
{
    char url[256];
    strncpy(url, _url, sizeof(url) - 1);
    url[sizeof(url) - 1] = '\0';
    
    char *pslash = strstr(url, "//");
    if (pslash)
    {
        strncpy(_protocol, url, pslash - url);
        _protocol[pslash - url] = '\0';
        strcpy(url, pslash + 2);
    }

    pslash = strchr(url, ':');
    if (!pslash)
    {
        *_port = -1;
        pslash = strchr(url, '/');
        if (!pslash)
        {
            strcpy(_host, url);
        }
        else
        {
            strncpy(_host, url, pslash - url);
            _host[pslash - url] = '\0';
            strcpy(path, pslash);
        }
    }
    else
    {
        strncpy(_host, url, pslash - url);
        _host[pslash - url] = '\0';
        strcpy(url, pslash + 1);
        pslash = strchr(url, '/');
        if (!pslash)
        {
            *_port = atoi(url);
        }
        else
        {
            char portStr[16];
            strncpy(portStr, url, pslash - url);
            portStr[pslash - url] = '\0';
            *_port = atoi(portStr);
            strcpy(path, pslash);
        }
    }
    return 0;
}

static int IsfirstMsg = 1;
static int DeviceId = 1;
static char writeBuffer[128];

int ws_callback(struct lws *_wsi, enum lws_callback_reasons _reasons, void *_user, void *_in, size_t _len)
{
    char buffer[2560] = {0};
    int len = 0;

    switch (_reasons)
    {
    case LWS_CALLBACK_CLIENT_ESTABLISHED:
        printf("Connection established\n");
        lws_callback_on_writable(_wsi);
        break;
    case LWS_CALLBACK_CLIENT_CLOSED:
        isBreak = 1;
        printf("Connection closed\n");
        break;
    case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
        printf("Connection error\n");
        break;
    case LWS_CALLBACK_CLIENT_RECEIVE:
        memcpy(buffer, _in, _len);
        printf("Received from server: %s\n", buffer);
        if (strcmp(buffer, "openCamera") == 0)
        {
            printf("Opening camera...\n");
            strcpy(writeBuffer, "CameraOK");
            lws_callback_on_writable(_wsi);
        }
        usleep(1000 * 1000);
        break;
    case LWS_CALLBACK_CLIENT_WRITEABLE:
        if (stop)
            break;
        if (IsfirstMsg)
        {
            snprintf(writeBuffer, sizeof(writeBuffer), "id:%d", DeviceId);
            IsfirstMsg = 0;
        }
        printf("Writing data: %s\n", writeBuffer);
        len = lws_write(_wsi, (unsigned char *)writeBuffer, strlen(writeBuffer), LWS_WRITE_TEXT);
        printf("Write length: %d\n", len);
        break;
    default:
        break;
    }
    return 0;
}

void *heartbeat_thread_func(void *arg)
{
    while (1)
    {
        if (!IsfirstMsg)
        {
            strcpy(writeBuffer, "beat");
            lws_callback_on_writable(wsi);
        }
        sleep(30);
    }
    return NULL;
}

int main(int argc, char **argv)
{
    if (argc < 2 || argc > 3)
    {
        printf("Usage: %s <url> [device_id]\n", argv[0]);
        return -1;
    }

    char protocol[16] = {0}, host[128] = {0}, path[128] = {0};
    int port = 0;

    UnmarshalURL(argv[1], protocol, host, &port, path);

    if (argc == 3)
        DeviceId = atoi(argv[2]);
    else
        DeviceId = 1;

    int ssl = (strcmp(protocol, "wss") == 0) ? 1 : 0;

    struct lws_context_creation_info info = {0};
    struct lws_client_connect_info ci = {0};
    struct lws_context *context;

    struct lws_protocols protocols[] = {
        {"ws-client", ws_callback, 0, 5120},
        {NULL, NULL, 0, 0}
    };

    info.protocols = protocols;
    info.port = CONTEXT_PORT_NO_LISTEN;
    info.options = ssl ? LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT : 0;

    context = lws_create_context(&info);
    if (!context)
    {
        printf("Failed to create context\n");
        return -1;
    }

    ci.context = context;
    ci.address = host;
    ci.port = port;
    ci.path = path;
    ci.host = ci.address;
    ci.origin = ci.address;
    ci.ssl_connection = ssl ? (LCCSCF_USE_SSL | LCCSCF_ALLOW_SELFSIGNED) : 0;
    ci.protocol = protocols[0].name;
    ci.pwsi = &wsi;

    lws_client_connect_via_info(&ci);

    pthread_t thread;
    if (pthread_create(&thread, NULL, heartbeat_thread_func, NULL) != 0)
    {
        printf("Failed to create heartbeat thread\n");
        return -1;
    }

    while (!isBreak)
    {
        lws_service(context, 500);
    }

    lws_context_destroy(context);
    return 0;
}
运行效果:
rv1106上运行异常
rv1106上运行异常
ubuntu上运行正常
ubuntu上运行正常
由于rv1106上的程序可以正常执行,也正常退出,应该不是编译器有问题。rv1106的系统时间也校正了,不会是时间不一致导致无法建立ws连接。问题可能出在哪里?

Re: libwebsockets异常断连(LWS_CALLBACK_CLIENT_CLOSED)

Posted: 2025-01-15 12:12
by Ryand
将while (!isBreak)修改为while(1)试试

Re: libwebsockets异常断连(LWS_CALLBACK_CLIENT_CLOSED)

Posted: 2025-01-23 7:49
by lyphotoes
我也在luckfox pico ultra w上交叉编译了libwebsockets,应用场景是作为服务端,对于客户端没有测试,附件中将我使用的库发给你,你可以直接替换试试,希望对你有帮助。