WebSocket服务器仅向wscat回显消息,无法推送至JavaScript客户端
问题解决:WebSocket服务器实现消息广播到所有客户端
你的核心问题是当前服务器仅将消息回传给发送消息的客户端(wscat),没有维护在线客户端的连接列表,无法实现消息广播到其他客户端(比如浏览器中的JS客户端)。以下是修改方案:
修改后的server.c代码
#include <libwebsockets.h> #include <string.h> #include <stdio.h> #include <pthread.h> // 全局连接链表,存储所有活跃的WebSocket连接 struct client_node { struct lws *wsi; struct client_node *next; }; static struct client_node *client_list = NULL; static pthread_mutex_t client_list_mutex = PTHREAD_MUTEX_INITIALIZER; // 将新连接加入链表 static void add_client(struct lws *wsi) { pthread_mutex_lock(&client_list_mutex); struct client_node *new_node = malloc(sizeof(struct client_node)); if (new_node) { new_node->wsi = wsi; new_node->next = client_list; client_list = new_node; printf("Client added, total connections: %d\n", lws_get_count_wsi(wsi->context)); } pthread_mutex_unlock(&client_list_mutex); } // 从链表移除断开的连接 static void remove_client(struct lws *wsi) { pthread_mutex_lock(&client_list_mutex); struct client_node **curr = &client_list; while (*curr) { if ((*curr)->wsi == wsi) { struct client_node *temp = *curr; *curr = (*curr)->next; free(temp); printf("Client removed, total connections: %d\n", lws_get_count_wsi(wsi->context)); break; } curr = &(*curr)->next; } pthread_mutex_unlock(&client_list_mutex); } // 向所有除发送方外的客户端广播消息 static void broadcast_message(struct lws *exclude_wsi, const unsigned char *msg, size_t len) { pthread_mutex_lock(&client_list_mutex); struct client_node *curr = client_list; while (curr) { if (curr->wsi != exclude_wsi && lws_is_valid_wsi(curr->wsi)) { unsigned char buffer[LWS_SEND_BUFFER_PRE_PADDING + len + LWS_SEND_BUFFER_POST_PADDING]; memcpy(&buffer[LWS_SEND_BUFFER_PRE_PADDING], msg, len); lws_write(curr->wsi, &buffer[LWS_SEND_BUFFER_PRE_PADDING], len, LWS_WRITE_TEXT); } curr = curr->next; } pthread_mutex_unlock(&client_list_mutex); } static int callback_ws(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { switch (reason) { case LWS_CALLBACK_ESTABLISHED: printf("Connection established\n"); add_client(wsi); break; case LWS_CALLBACK_CLOSED: printf("Connection closed\n"); remove_client(wsi); break; case LWS_CALLBACK_RECEIVE: printf("Received message length: %d\n", (int)len); char buffer[1024]; if (len < sizeof(buffer) - 1) { memcpy(buffer, in, len); buffer[len] = '\0'; printf("Message received: %s\n", buffer); // 广播消息到所有其他客户端 broadcast_message(wsi, (unsigned char*)buffer, len); // 可选:保留回显给发送方的逻辑 // unsigned char echo_msg[LWS_SEND_BUFFER_PRE_PADDING + len + LWS_SEND_BUFFER_POST_PADDING]; // memcpy(&echo_msg[LWS_SEND_BUFFER_PRE_PADDING], buffer, len); // lws_write(wsi, &echo_msg[LWS_SEND_BUFFER_PRE_PADDING], len, LWS_WRITE_TEXT); } break; default: break; } return 0; } static struct lws_protocols protocols[] = { { "ws", callback_ws, 0, 1024 }, { NULL, NULL, 0, 0 } // Terminator }; int main(void) { struct lws_context_creation_info info; memset(&info, 0, sizeof info); info.port = 8080; info.protocols = protocols; struct lws_context *context = lws_create_context(&info); if (context == NULL) { fprintf(stderr, "lws init failed\n"); return -1; } printf("Starting server on port 8080...\n"); while (1) { lws_service(context, 1000); } lws_context_destroy(context); return 0; }
关键改动说明
- 维护客户端连接列表:用链表存储所有活跃的
struct lws*连接实例,配合互斥锁保证线程安全(即使libwebsockets使用多线程服务,也能避免并发访问问题)。 - 连接生命周期管理:
LWS_CALLBACK_ESTABLISHED:新客户端连接时,将其加入链表。LWS_CALLBACK_CLOSED:客户端断开连接时,从链表中移除。
- 消息广播逻辑:收到消息后,遍历连接列表,将消息发送给所有非发送方的客户端,实现wscat发送的命令同步到浏览器JS客户端。
验证步骤
- 重新编译服务器:
gcc server.c -o server -lwebsockets -lpthread - 启动服务器:
./server - 打开浏览器访问
index.html,确认控制台显示连接成功。 - 用wscat连接服务器:
wscat -c ws://localhost:8080 - 在wscat中发送颜色命令(比如
red或#ff0000),检查浏览器中的SVG圆形颜色是否同步变化。
内容的提问来源于stack exchange,提问作者mnekkach
相关产品推荐
相关产品推荐

