最简单的c语言websocket后端+https前端 ssl加密例程

前言

发现网上大多是webscoket加 http形式的例程,很少有https的例程。

亲自操作了一遍,总结一下如何使用建立https形式的websocket,最关键的是https必须通过网页访问,所以增加了前端例程。代码放到最后面了。

websocket使用ssl很简单。只需要以下步骤:

1. 通过openssl生成证书

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes

2. 在后端代码中代码中增加 证书、私钥路径,并打开ssl

 

3. 在编译时增加 -lssl -lcrypto

gcc -o websocket_server webss.c -lwebsockets -lssl -lcrypto

4. 在前端用wss打开

const socket = new WebSocket("wss://10.29.60.104:8080", "ws-protocol");

具体操作过程如下:

1. 编译安装libwebsocket.so

mkdir webs
cd webs/
apt install git
git clone https://github.com/warmcat/libwebsockets
cd libwebsockets/
mkdir build && cd build
cmake .. -DLWS_WITHOUT_TESTAPPS=ON
make && sudo make install

2.  编译服务端程序

cd ..
touch webss.c
gcc -o websocket_server webss.c -lwebsockets -lssl -lcrypto
 
添加路径
sudo find / -name "libwebsockets.so*" 2>/dev/null
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH

生成证书
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes

./websocket_server

3. 前端

sudo npm install http-server -g
npm install -g http-server@0.12.3  # 兼容旧版 Node.js

#该处端口不能与后端websocket端口相同,后端例程使用8080

http方式
http-server  -p 8000

https方式
http-server --ssl --cert ./cert.pem --key ./key.pem -p 8000

指定路径https方式
http-server /home/lzh/gccmake/index.html --ssl --cert ./cert.pem --key ./key.pem -p 8000

web

注意


1. 前端网页端口(示例中8000)和 webscoket端口(示例8080)不能一样
2. 内网ip证书无法生成可信任证书
3. 使用 OpenSSL 测试加密链路
openssl s_client -connect 10.29.60.104:8000 -servername example.com | grep "Cipher"

4. 8000/8080端口要确保没被占用,可以用任意未使用的端口

5. 修改适配只需要修改下面两个文件中网卡ip和端口即可。

6. 低版本http-server无法显示中文,若使用高版本http-server需要确保node.js版本支持

代码

webss.c

#include <libwebsockets.h>
#include <string.h>

#define PORT 8080

// 定义连接池
static struct lws *clients[10];
static int client_count = 0;

// WebSocket 协议回调
static int ws_callback(struct lws *wsi, enum lws_callback_reasons reason,
                       void *user, void *in, size_t len) {
    switch (reason) {
        // 新连接建立
        case LWS_CALLBACK_ESTABLISHED:
            printf("Client connected\n");
            clients[client_count++] = wsi;  // 添加到连接池
            break;

        // 收到消息
        case LWS_CALLBACK_RECEIVE:
            printf("Received: %s\n", (char *)in);
            // 广播消息给所有客户端
            for (int i = 0; i < client_count; i++) {
                //if (clients[i] != wsi) 
                {  // 不发送给自己
                    lws_write(clients[i], in, len, LWS_WRITE_TEXT);
                }
            }
            break;

        // 连接关闭
        case LWS_CALLBACK_CLOSED:
            printf("Client disconnected\n");
            // 从连接池移除
            for (int i = 0; i < client_count; i++) {
                if (clients[i] == wsi) {
                    clients[i] = clients[--client_count];
                    break;
                }
            }
            break;

        default:
            break;
    }
    return 0;
}

// 支持的协议列表
static struct lws_protocols protocols[] = {
    {
        "ws-protocol",    // 协议名(客户端需匹配)
        ws_callback,      // 回调函数
        0,               // 每会话内存大小
        0,               // 最大帧大小
    },
    { NULL, NULL, 0, 0 }  // 结束标记
};

int main() {
    struct lws_context_creation_info info;
    struct lws_context *context;

    memset(&info, 0, sizeof(info));
    info.port = PORT;
    //info.port = 443;
    info.iface = "10.29.60.104";  // 绑定到指定 IP
    info.protocols = protocols;
    info.gid = -1;
    info.uid = -1;
    info.ssl_cert_filepath = "./cert.pem";  // 证书路径
    info.ssl_private_key_filepath = "./key.pem"; // 私钥路径
    info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;    //打开ssl

    // 创建 WebSocket 上下文
    context = lws_create_context(&info);
    if (!context) {
        fprintf(stderr, "Failed to create WebSocket context\n");
        return 1;
    }

    printf("WebSocket server started on port %d\n", PORT);

    // 事件循环
    while (1) {
        lws_service(context, 50);  // 50ms 超时
    }

    lws_context_destroy(context);
    return 0;
}

index.html

<!DOCTYPE html>
<html>
<head>
    <title>WebSocket 客户端</title>
</head>
<body>
    <h1>WebSocket 客户端</h1>
    <div>
        <input type="text" id="messageInput" placeholder="输入消息">
        <button onclick="sendMessage()">发送</button>
    </div>
    <div id="messages"></div>

    <script>

        const socket = new WebSocket("wss://10.29.60.104:8080", "ws-protocol");
        
        socket.onopen = function(e) {
            console.log("[open] 连接建立");
            addMessage("系统: 已连接到服务器");
        };
        
        socket.onmessage = function(event) {
            console.log(`[message] 收到数据: ${event.data}`);
            addMessage(`服务器: ${event.data}`);
        };
        
        socket.onclose = function(event) {
            if (event.wasClean) {
                console.log(`[close] 连接关闭,代码=${event.code} 原因=${event.reason}`);
                addMessage(`系统: 连接已关闭 (${event.reason})`);
            } else {
                console.log('[close] 连接断开');
                addMessage('系统: 连接意外断开');
            }
        };
        
        socket.onerror = function(error) {
            console.log(`[error] ${error.message}`);
            addMessage(`系统: 发生错误 - ${error.message}`);
        };
        
        function sendMessage() {
            const input = document.getElementById("messageInput");
            const message = input.value+'\0';
            
            if (message) {
                console.log(`发送: ${message}`);
                socket.send(message);
                addMessage(`你: ${message}`);
                input.value = "";
            }
        }
        
        function addMessage(text) {
            const messages = document.getElementById("messages");
            const messageElement = document.createElement("div");
            messageElement.textContent = text;
            messages.appendChild(messageElement);
        }
    </script>
</body>
</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值