WebSocket是一种基于TCP协议的双向通信协议,可在客户端和服务器之间进行实时通信。下面是使用C语言实现WebSocket的步骤:

  1. 建立TCP连接:使用socket API函数创建客户端套接字,然后使用connect函数连接到服务器。

  2. 发送WebSocket握手请求:客户端发送HTTP GET请求,请求升级到WebSocket连接。请求头中包含Sec-WebSocket-Key和Sec-WebSocket-Version字段,分别表示随机生成的字符串和WebSocket版本号。

  3. 接收WebSocket握手响应:服务器响应HTTP 101 Switching Protocols状态码,表示成功升级到WebSocket连接。响应头中包含Sec-WebSocket-Accept字段,表示服务器同意升级。客户端验证Sec-WebSocket-Accept字段是否正确,以确保连接是安全的。

  4. 发送和接收数据:客户端和服务器可以通过send和recv函数发送和接收数据,数据格式为WebSocket帧。WebSocket帧分为控制帧和数据帧,控制帧用于控制连接状态,数据帧用于传输数据。

  5. 断开WebSocket连接:客户端发送Close帧,表示断开连接。服务器发送Close帧作为响应,然后关闭连接。

示例代码:

客户端:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define SERVER_PORT 8080
#define SERVER_ADDR "127.0.0.1"

void send_handshake(int sockfd)
{
    char buf[1024];
    sprintf(buf, "GET / HTTP/1.1\r\n"
                 "Host: %s:%d\r\n"
                 "Upgrade: websocket\r\n"
                 "Connection: Upgrade\r\n"
                 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
                 "Sec-WebSocket-Version: 13\r\n"
                 "\r\n", SERVER_ADDR, SERVER_PORT);
    send(sockfd, buf, strlen(buf), 0);
}

void recv_handshake(int sockfd)
{
    char buf[1024];
    recv(sockfd, buf, sizeof(buf), 0);
    printf("%s\n", buf);
}

void send_frame(int sockfd, char *data)
{
    char buf[1024];
    int len = strlen(data);
    buf[0] = 0x81;  // FIN + TEXT
    if (len <= 125) {
        buf[1] = len;
        memcpy(buf + 2, data, len);
        send(sockfd, buf, len + 2, 0);
    } else if (len <= 65535) {
        buf[1] = 126;
        buf[2] = len >> 8;
        buf[3] = len & 0xff;
        memcpy(buf + 4, data, len);
        send(sockfd, buf, len + 4, 0);
    } else {
        buf[1] = 127;
        buf[2] = 0;
        buf[3] = 0;
        buf[4] = 0;
        buf[5] = 0;
        buf[6] = len >> 24;
        buf[7] = (len >> 16) & 0xff;
        buf[8] = (len >> 8) & 0xff;
        buf[9] = len & 0xff;
        memcpy(buf + 10, data, len);
        send(sockfd, buf, len + 10, 0);
    }
}

void recv_frame(int sockfd)
{
    char buf[1024];
    recv(sockfd, buf, sizeof(buf), 0);
    int opcode = buf[0] & 0x0f;
    int fin = buf[0] & 0x80;
    int mask = buf[1] & 0x80;
    int len = buf[1] & 0x7f;
    if (len == 126) {
        len = (buf[2] << 8) | buf[3];
    } else if (len == 127) {
        len = (buf[6] << 24) | (buf[7] << 16) | (buf[8] << 8) | buf[9];
    }
    if (mask) {
        char *mask_key = buf + 2;
        char *data = buf + 6;
        for (int i = 0; i < len; i++) {
            data[i] ^= mask_key[i % 4];
        }
    } else {
        char *data = buf + 2;
    }
    printf("%.*s\n", len, data);
}

int main()
{
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(SERVER_PORT);
    servaddr.sin_addr.s_addr = inet_addr(SERVER_ADDR);
    connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    send_handshake(sockfd);
    recv_handshake(sockfd);
    send_frame(sockfd, "hello");
    recv_frame(sockfd);
    close(sockfd);
    return 0;
}

服务器:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define SERVER_PORT 8080
#define SERVER_ADDR "127.0.0.1"

void send_handshake(int sockfd)
{
    char buf[1024];
    recv(sockfd, buf, sizeof(buf), 0);
    printf("%s\n", buf);
    char *key = strstr(buf, "Sec-WebSocket-Key: ");
    if (key) {
        key += strlen("Sec-WebSocket-Key: ");
        char *end = strchr(key, '\r');
        if (end) {
            *end = '\0';
            strcat(key, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
            unsigned char sha1[20];
            SHA1((unsigned char *)key, strlen(key), sha1);
            char accept[32];
            base64_encode(sha1, 20, accept);
            sprintf(buf, "HTTP/1.1 101 Switching Protocols\r\n"
                         "Upgrade: websocket\r\n"
                         "Connection: Upgrade\r\n"
                         "Sec-WebSocket-Accept: %s\r\n"
                         "\r\n", accept);
            send(sockfd, buf, strlen(buf), 0);
        }
    }
}

void recv_frame(int sockfd)
{
    char buf[1024];
    recv(sockfd, buf, sizeof(buf), 0);
    int opcode = buf[0] & 0x0f;
    int fin = buf[0] & 0x80;
    int mask = buf[1] & 0x80;
    int len = buf[1] & 0x7f;
    if (len == 126) {
        len = (buf[2] << 8) | buf[3];
    } else if (len == 127) {
        len = (buf[6] << 24) | (buf[7] << 16) | (buf[8] << 8) | buf[9];
    }
    if (mask) {
        char *mask_key = buf + 2;
        char *data = buf + 6;
        for (int i = 0; i < len; i++) {
            data[i] ^= mask_key[i % 4];
        }
    } else {
        char *data = buf + 2;
    }
    printf("%.*s\n", len, data);
    send(sockfd, buf, len + 2, 0);
}

int main()
{
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(SERVER_PORT);
    servaddr.sin_addr.s_addr = inet_addr(SERVER_ADDR);
    bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    listen(sockfd, 5);
    int connfd = accept(sockfd, NULL, NULL);
    send_handshake(connfd);
    while (1) {
        recv_frame(connfd);
    }
    close(sockfd);
    return 0;
}
``
websocket C语言实现

原文地址: https://www.cveoy.top/t/topic/hfMB 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录