将WebSockets消息发送到服务器

程序员

我正在尝试使用一种设备的API,但是它使用的是带有强制执行的Origin标头的WS接口,这给我带来了麻烦。

在Chrome中,我可以在加载具有正确Origin的页面时打开控制台,创建WS连接,并轻松发送/接收消息:WS连接已创建,消息已发送和接收请注意,服务器始终会确认发送的消息(绿色)。

作为参考,如果在另一个页面上创建连接会导致Origin标头不匹配(报告为404),则会发生这种情况: 使用错误的Origin标头创建的WS连接

为了避开这个问题,我转向了C语言,因为我的程序的其余部分还是以这种方式编写的。这是我现在拥有的代码,主要基于以下答案

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

#define KGRN "\033[0;32;32m"
#define KCYN "\033[0;36m"
#define KRED "\033[0;32;31m"
#define KYEL "\033[1;33m"
#define KBLU "\033[0;32;34m"
#define KCYN_L "\033[1;36m"
#define KBRN "\033[0;33m"
#define RESET "\033[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;
};

struct pthread_routine_tool {
    struct lws_context *context;
    struct lws *wsi;
};

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;
            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 recvived:%s\n"RESET, (char *)in);

            if (writeable_flag)
                destroy_flag = 1;

            break;
        case LWS_CALLBACK_CLIENT_WRITEABLE :
            printf(KYEL"[Main Service] On writeable is called. send byebye message\n"RESET);
            websocket_write_back(wsi, "{\"command\":\"subscribe\",\"identifier\":\"{\\\"channel\\\":\\\"DevicesChannel\\\",\\\"share_token\\\":\\\"D0E91\\\"}\"}", -1);
            websocket_write_back(wsi, "{\"command\":\"message\",\"identifier\":\"{\\\"channel\\\":\\\"DevicesChannel\\\",\\\"share_token\\\":\\\"D0E91\\\"}\",\"data\":\"{\\\"value\\\":100,\\\"action\\\":\\\"set_buzz\\\"}\"}", -1);
            writeable_flag = 1;
            break;

        default:
            break;
    }

    return 0;
}

static void *pthread_routine(void *tool_in)
{
    struct pthread_routine_tool *tool = tool_in;

    printf(KBRN"[pthread_routine] Good day. This is pthread_routine.\n"RESET);

    //* waiting for connection with server done.*/
    while(!connection_flag)
        usleep(1000*20);

    //*Send greeting to server*/ 
    lws_callback_on_writable(tool->wsi);

}

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  = "websockets";
    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, "mobu1.herokuapp.com", 443, 1,
        "/cable", "mobu1.herokuapp.com", "link.motorbunny.com",
    if (wsi == NULL) {
        printf(KRED"[Main] wsi create error.\n"RESET);
        return -1;
    }

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

    struct pthread_routine_tool tool;
    tool.wsi = wsi;
    tool.context = context;

    pthread_t pid;
    pthread_create(&pid, NULL, pthread_routine, &tool);
    pthread_detach(pid);

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

    lws_context_destroy(context);

    return 0;
}

The result of running the above program is this: 来自服务器的WS消息

As you can see, the periodic pings from server to my client are being picked up, but the lws_callback_on_writable(wsi); seems to have no effect as the LWS_CALLBACK_CLIENT_WRITEABLE callback never gets called. Additionally, if I call websocket_write_back() directly anywhere else, it doesn't seem to be sending anything to the server, and no acknowledgement is present either.

Is there something obvious I am doing wrong?

EDIT 1: I found this neat wscat, where I can replicate the results from Chrome: wscat作品 Now the question is, how can I interface this with my C program in a way that it can wait for the Welcome message from the server, and then send two messages? And better yet, how to stay connected, so that my program can send multiple commands at different points of time without having to do the handshake all the time?

programagor

The reason why the LWS_CALLBACK_CLIENT_WRITEABLE callback never got called was because this particular server uses non-standard handshake. So, to bypass this, I forked a fork of libwsclient and modified the handshake checking function to not fail on mismatch. I also added an optional Origin header.

Now, all I need to do in my original program is

wsclient *client;
char sync_str[6];
void mb_send(int power, char* type)
{
  char cmd[2048];
  sprintf (cmd, "{\"command\":\"message\",\"identifier\":\"{\\\"channel\\\":\\\"DevicesChannel\\\",\\\"share_token\\\":\\\"%s\\\"}\",\"data\":\"{\\\"value\\\":%d,\\\"action\\\":\\\"set_%s\\\"}\"}",sync_str,power,type);
  libwsclient_send(client,cmd);
}
void mb_connect()
{
  char cmd[2048];
  sprintf (cmd, "{\"command\":\"subscribe\",\"identifier\":\"{\\\"channel\\\":\\\"DevicesChannel\\\",\\\"share_token\\\":\\\"%s\\\"}\"}",sync_str);
  libwsclient_send(client,cmd);
  mb_send(0,"buzz");
}
int nop()
{
  return 0;
}
int main()
{
  client = libwsclient_new_extra("wss://mobu1.herokuapp.com/cable","https://link.motorbunny.com");
  if(!client) {
    fprintf(stderr, "Unable to initialize new WS client.\n");
    exit(1);
  }

  libwsclient_onopen(client, &nop);
  libwsclient_onmessage(client, &nop);
  libwsclient_onerror(client, &nop);
  libwsclient_onclose(client, &nop);

  libwsclient_run(client);

  ...
  mb_connect();
  ...  
  mb_send(200,"buzz");
  mb_send(40,"twirl");
  ...
  mb_send(0,"buzz");
  mb_send(0,"twirl");
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

Kafka-无法使用Java将消息发送到远程服务器

使用其ID将消息发送到特定服务器-discord.py

如何将SWFT消息发送到远程服务器上的MQ?

如何将消息从golang的websocket服务器主动发送到客户端

MultipartEntityBuilder将图片发送到铁路服务器

无法使用Logstash将消息发送到Graylog服务器

GCM连接服务器如何将消息发送到Android设备?

Flask SocketIO将消息从服务器发送到房间

将jsPDF生成的PDF发送到服务器

将加密的消息从python客户端发送到Node.js服务器

将服务器端系统消息发送到通道?

尝试将telnet命令发送到服务器

将键值对发送到存储服务器

将多个图像发送到Web服务器

将消息从Node.js服务器发送到Windows计算机

JavaPNS为什么将生产推送消息发送到沙盒服务器?

将信息从服务器发送到android应用

将事件从服务器发送到ios应用

如何使用C ++中的Websocket客户端将消息发送到服务器?

如何获取从服务器发送到Android的消息

无法将数据发送到libwebsocket服务器

服务器如何使用Java将消息发送到客户端

Socket.io服务器到服务器(将消息发送到特定服务器)

Volley将空参数发送到服务器

将img发送到服务器

将字符串消息从Netty客户端发送到服务器

如何使用带代理的Signalr将消息从客户端发送到服务器?

Spring Integration TCP服务器将消息发送到TCP客户端

Node.js WebSockets - 使用 BasicAuth 将数据发送到服务器