WebSocket-Implementierung für eingebettete Geräte

Hier ist ein grundlegender Beispielcode für die Implementierung einer WebSocket-Verbindung mit jQuery:

// 声明 websocket 变量
var webSocket;

// 与服务器建立连接
function connect() {
  webSocket = new WebSocket("ws://localhost:8080");

  // 连接成功时触发的事件
  webSocket.onopen = function(event) {
    console.log("WebSocket连接已建立");
  };

  // 接收到消息时触发的事件
  webSocket.onmessage = function(event) {
    console.log("接收到消息:" + event.data);
  };

  // 连接关闭时触发的事件
  webSocket.onclose = function(event) {
    console.log("WebSocket连接已关闭");
  };

  // 发生错误时触发的事件
  webSocket.onerror = function(event) {
    console.log("WebSocket连接发生错误");
  };
}

// 向服务器发送消息
function sendMsg() {
  var msg = $("#msg").val();
  webSocket.send(msg);
}

// 关闭 WebSocket 连接
function closeWebSocket() {
  webSocket.close();
}

// 初始化函数
$(document).ready(function() {
  $("#connectBtn").click(function() {
    connect();
  });

  $("#sendBtn").click(function() {
    sendMsg();
  });

  $("#closeBtn").click(function() {
    closeWebSocket();
  });
});

Im obigen Code haben wir webSocketdie Variable und dann drei Methoden definiert connect(), die zum Herstellen einer Verbindung, zum Senden einer Nachricht bzw. zum Schließen der Verbindung verwendet werden. In der Initialisierungsfunktion verwenden wir die Methode um das Klickereignis der Schaltfläche zu binden, und rufen dann jeweils die oben genannten drei Methoden auf.sendMsg()closeWebSocket()click()

Es ist zu beachten, dass der obige Code nur ein Beispielcode ist und entsprechend der spezifischen Situation bei der tatsächlichen Verwendung geändert werden muss. Bei der Nutzung der WebSocket-Kommunikation müssen Sie auch auf Aspekte wie den domänenübergreifenden Zugriff achten.

Das Folgende ist ein Beispielcode für die Entwicklung von WebSockets für eingebettete Geräte mit der Sprache C. Der Code verwendet die Geräteseite als Serverseite, um mit der Webseite zu interagieren:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

// 定义websocket协议的一些常量
#define WS_MAGIC "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
#define WS_HEADER_LEN 2
#define WS_MASK_LEN 4
#define WS_FIN_BIT 0x80
#define WS_OPCODE_MASK 0x0f
#define WS_MASK_BIT 0x80
#define WS_PAYLOAD_LEN_MASK 0x7f

// websocket帧类型
enum ws_opcode {
    WS_OPCODE_CONTINUATION = 0x0,
    WS_OPCODE_TEXT = 0x1,
    WS_OPCODE_BINARY = 0x2,
    WS_OPCODE_CLOSE = 0x8,
    WS_OPCODE_PING = 0x9,
    WS_OPCODE_PONG = 0xa
};

// 创建websocket连接并进行握手
int ws_connect(char *address, int port)
{
    // 创建TCP套接字
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("socket");
        return -1;
    }

    // 设置套接字选项
    int flags = fcntl(sockfd, F_GETFL, 0);
    if (flags == -1) {
        close(sockfd);
        perror("fcntl");
        return -1;
    }
    if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) == -1) {
        close(sockfd);
        perror("fcntl");
        return -1;
    }

    // 构造连接地址
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(address);
    addr.sin_port = htons(port);

    // 连接到服务器
    int ret = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));
    if (ret == -1 && errno != EINPROGRESS) {
        close(sockfd);
        perror("connect");
        return -1;
    }

    // 等待连接完成
    fd_set write_fds;
    FD_ZERO(&write_fds);
    FD_SET(sockfd, &write_fds);
    ret = select(sockfd + 1, NULL, &write_fds, NULL, NULL);
    if (ret == -1) {
        close(sockfd);
        perror("select");
        return -1;
    }

    // 检查连接是否成功
    int error = 0;
    socklen_t len = sizeof(error);
    if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) == -1 || error != 0) {
        close(sockfd);
        perror("getsockopt");
        return -1;
    }

    // 发送握手请求
    char request[1024];
    snprintf(request, sizeof(request), "GET / HTTP/1.1\r\n" 
            "Upgrade: websocket\r\n"
            "Connection: Upgrade\r\n"
            "Sec-WebSocket-Version: 13\r\n"
            "Host: %s:%d\r\n"
            "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
            "\r\n",
            address, port);

    ret = write(sockfd, request, strlen(request));
    if (ret == -1) {
        close(sockfd);
        perror("write");
        return -1;
    }

    // 读取握手响应
    char response[1024];
    ret = read(sockfd, response, sizeof(response) - 1);
    if (ret == -1) {
        close(sockfd);
        perror("read");
        return -1;
    }
    response[ret] = '\0';

    // 解析握手响应
    char *p = strstr(response, "\r\n\r\n") + 4;
    char buf[1024];
    snprintf(buf, sizeof(buf), "%s%s", p, WS_MAGIC);

    char sha1[20];
    mbedtls_sha1((const unsigned char *)buf, strlen(buf), (unsigned char *)sha1);

    char output[sizeof(sha1) * 2 + 1];
    for(int i = 0; i < sizeof(sha1); i++) {
        sprintf(output + i * 2, "%02x", sha1[i]);
    }

    // 发送握手响应
    char handshake[1024];
    snprintf(handshake, sizeof(handshake), "HTTP/1.1 101 Switching Protocols\r\n"
            "Upgrade: websocket\r\n"
            "Connection: Upgrade\r\n"
            "Sec-WebSocket-Accept: %s\r\n"
            "\r\n",
            output);

    ret = write(sockfd, handshake, strlen(handshake));
    if (ret == -1) {
        close(sockfd);
        perror("write");
        return -1;
    }

    return sockfd;
}

// 发送websocket数据帧
int ws_send(int sockfd, enum ws_opcode opcode, char *data, int len)
{
    // 构造websocket头部
    unsigned char header[14];
    memset(header, 0, 14);
    header[0] = WS_FIN_BIT | opcode;
    if (len < 126) {
        header[1] = len | WS_MASK_BIT;
        header[2] = 0x01; // 随机生成掩码
        header[3] = 0x02; // 随机生成掩码
        header[4] = 0x03; // 随机生成掩码
        header[5] = 0x04; // 随机生成掩码
    } else if (len < 65536) {
        header[1] = 0x7e | WS_MASK_BIT;
        header[2] = (len >> 8) & 0xff;
        header[3] = len & 0xff;
        header[4] = 0x01; // 随机生成掩码
        header[5] = 0x02; // 随机生成掩码
        header[6] = 0x03; // 随机生成掩码
        header[7] = 0x04; // 随机生成掩码
    } else {
        header[1] = 0x7f | WS_MASK_BIT;
        header[2] = (len >> 56) & 0xff;
        header[3] = (len >> 48) & 0xff;
        header[4] = (len >> 40) & 0xff;
        header[5] = (len >> 32) & 0xff;
        header[6] = (len >> 24) & 0xff;
        header[7] = (len >> 16) & 0xff;
        header[8] = (len >> 8) & 0xff;
        header[9] = len & 0xff;
        header[10] = 0x01; // 随机生成掩码
        header[11] = 0x02; // 随机生成掩码
        header[12] = 0x03; // 随机生成掩码
        header[13] = 0x04; // 随机生成掩码
    }

    // 发送websocket数据帧
    int ret = write(sockfd, header, WS_HEADER_LEN + WS_MASK_LEN);
    if (ret == -1) {
        close(sockfd);
        perror("write");
        return -1;
    }

    ret = write(sockfd, data, len);
    if (ret == -1) {
        close(sockfd);
        perror("write");
        return -1;
    }

    return 0;
}

// 接收websocket数据帧
int ws_recv(int sockfd, enum ws_opcode *opcode, char **data, int *len)
{
    // 读取websocket头部
    unsigned char header[14];
    memset(header, 0, 14);

    int ret = read(sockfd, header, WS_HEADER_LEN);
    if (ret == -1) {
        close(sockfd);
        perror("read");
        return -1;
    }
    if (ret == 0) {
        close(sockfd);
        return -1;
    }

    if (!(header[0] & WS_FIN_BIT)) {
        printf("fragmented frame received\n");
        return -1;
    }

    *opcode = header[0] & WS_OPCODE_MASK;

    int has_mask = header[1] & WS_MASK_BIT;
    *len = header[1] & WS_PAYLOAD_LEN_MASK;

    unsigned char mask[4];
    if (has_mask) {
        ret = read(sockfd, mask, WS_MASK_LEN);
        if (ret == -1) {
            close(sockfd);
            perror("read");
            return -1;
        }
    }

    // 读取websocket数据
    char *buf = malloc(*len + 1);
    memset(buf, 0, *len + 1);

    ret = read(sockfd, buf, *len);
    if (ret == -1) {
        close(sockfd);
        perror("read");
        free(buf);
        return -1;
    }
    if (ret != *len) {
        printf("incomplete frame received\n");
        free(buf);
        return -1;
    }

    // 解码websocket数据
    if (has_mask) {
        for (int i = 0; i < *len; i++) {
            buf[i] ^= mask[i % 4];
        }
    }

    *data = buf;

    return 0;
}

int main(int argc, char *argv[])
{
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <port>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    int port = atoi(argv[1]);

    // 监听端口并等待连接
    int sockfd = ws_connect("localhost", port);
    if (sockfd == -1) {
        perror("ws_connect");
        exit(EXIT_FAILURE);
    }

    printf("Connected to server\n");

    while (1) {
        // 接收websocket数据帧
        enum ws_opcode opcode;
        char *data = NULL;
        int len;

        int ret = ws_recv(sockfd, &opcode, &data, &len);
        if (ret == -1) {
            perror("ws_recv");
            exit(EXIT_FAILURE);
        }

        // 处理websocket数据帧
        switch (opcode) {
            case WS_OPCODE_TEXT:
                printf("Recv text: %s\n", data);

                // 发送回应
                ws_send(sockfd, WS_OPCODE_TEXT, data, len);
                break;

            case WS_OPCODE_BINARY:
                printf("Recv binary data with length %d\n", len);

                // 发送回应
                ws_send(sockfd, WS_OPCODE_BINARY, data, len);
                break;

            case WS_OPCODE_CLOSE:
                printf("Recv close frame\n");

                // 发送关闭响应并退出循环
                ws_send(sockfd, WS_OPCODE_CLOSE, NULL, 0);
                goto exit_loop;

            default:
                printf("Invalid opcode %d\n", opcode);
                break;
        }

        free(data);
    }

exit_loop:
    close(sockfd);

    return EXIT_SUCCESS;
}

Der Beispielcode implementiert einen einfachen Websocket-Server, der den angegebenen Port abhört, darauf wartet, dass der Client eine Verbindung herstellt, und auf die empfangenen Websocket-Datenrahmen verschiedener Typen antwortet. Sie können das Programm ausführen und dann JavaScript verwenden, um auf der Webseite zu schreiben und mit dem WebSocket-Client zu interagieren.

Supongo que te gusta

Origin blog.csdn.net/jhyBOSS/article/details/130080368
Recomendado
Clasificación