嵌入式设备websocket实现

以下是使用 jQuery 实现 WebSocket 连接的基本示例代码:

// 声明 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();
  });
});

上述代码中,我们声明了 webSocket 变量用来保存 WebSocket 连接对象,然后定义了 connect()sendMsg()closeWebSocket() 三个方法分别用来建立连接、发送消息和关闭连接。在初始化函数中,我们使用 jQuery 的 click() 方法来绑定按钮的点击事件,然后分别调用上述三个方法。

需要注意的是,以上代码仅为示例代码,实际使用时需要根据具体情况进行修改。在使用 WebSocket 通信时,还需要注意跨域访问等问题。

以下是使用C语言实现嵌入式设备开发websocket的示例代码,该代码为设备端作为server端与网页进行交互:

#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;
}

该示例代码实现了一个简单的websocket server,它监听指定的端口并等待客户端连接,对于接收到的不同类型的websocket数据帧作出回应。你可以运行该程序,然后在网页中使用JavaScript编写websocket client并与之交互。

猜你喜欢

转载自blog.csdn.net/jhyBOSS/article/details/130080368
今日推荐