UNIX STREAM Socket服务器重复接收相同消息问题求助
UNIX STREAM Socket 重复接收相同消息问题排查与解决
问题现象
- Linux环境下,UNIX STREAM Socket客户端仅发送1次消息(消息为每次全新生成,无静态变量复用导致重复的情况),但服务器在接收第一条消息后,持续打印相同内容
- 客户端基于libev处理套接字,服务器使用select模型
排查过程
- 系统调用追踪:通过
strace分析发现,服务器周期性触发读事件,每次读取到相同消息;但客户端仅执行过1次write操作,排除客户端重复发送的可能 - 代码逻辑校验:确认客户端消息生成逻辑无静态变量复用,排除代码层面的重复发送问题
- 函数调用溯源:最终定位到发送消息的
send_event函数被编译进libabc.so共享库,另有一个守护进程通过调用该库的包装函数,重复触发了send_event,导致服务器持续收到重复消息
解决方案
通过PID校验限制仅目标客户端进程触发消息发送:
- 客户端启动时创建
.pid文件,写入自身进程PID - 在
send_event函数中,读取.pid文件中的目标PID,校验当前进程PID与目标PID是否一致,仅当匹配时才执行消息发送操作
核心代码片段
客户端核心代码(libev处理)
#include <ev.h> #include <unistd.h> #include <fcntl.h> #include <stdlib.h> #include <string.h> static void send_message(struct ev_loop *loop, ev_io *w, int revents) { char msg[64]; // 生成随机消息(确保无静态变量复用) snprintf(msg, sizeof(msg), "test_msg_%ld", random()); write(w->fd, msg, strlen(msg)); // 仅发送一次,停止监听写事件 ev_io_stop(loop, w); } int main() { // 写入客户端PID到文件 int fd = open("/tmp/client.pid", O_CREAT|O_WRONLY|O_TRUNC, 0644); if (fd != -1) { char pid_str[16]; snprintf(pid_str, sizeof(pid_str), "%d", getpid()); write(fd, pid_str, strlen(pid_str)); close(fd); } struct ev_loop *loop = EV_DEFAULT; ev_io write_watcher; int sock_fd = socket(AF_UNIX, SOCK_STREAM, 0); struct sockaddr_un addr = {0}; addr.sun_family = AF_UNIX; strcpy(addr.sun_path, "/tmp/test_socket"); connect(sock_fd, (struct sockaddr*)&addr, sizeof(addr)); ev_io_init(&write_watcher, send_message, sock_fd, EV_WRITE); ev_io_start(loop, &write_watcher); ev_run(loop, 0); close(sock_fd); return 0; }
服务器核心代码(select模型)
#include <sys/select.h> #include <sys/un.h> #include <unistd.h> #include <stdio.h> #include <string.h> int main() { unlink("/tmp/test_socket"); int sock_fd = socket(AF_UNIX, SOCK_STREAM, 0); struct sockaddr_un addr = {0}; addr.sun_family = AF_UNIX; strcpy(addr.sun_path, "/tmp/test_socket"); bind(sock_fd, (struct sockaddr*)&addr, sizeof(addr)); listen(sock_fd, 5); fd_set read_fds; char buf[64]; while(1) { FD_ZERO(&read_fds); FD_SET(sock_fd, &read_fds); select(sock_fd+1, &read_fds, NULL, NULL, NULL); if(FD_ISSET(sock_fd, &read_fds)) { int conn_fd = accept(sock_fd, NULL, NULL); ssize_t read_len; while((read_len = read(conn_fd, buf, sizeof(buf)-1)) > 0) { buf[read_len] = '\0'; printf("Received: %s\n", buf); memset(buf, 0, sizeof(buf)); } close(conn_fd); } } close(sock_fd); return 0; }
strace关键日志(服务器侧)
# 服务器重复触发读事件并读取相同内容 select(4, [3], NULL, NULL, NULL) = 1 (in [3]) accept(3, {sa_family=AF_UNIX, sun_path="/tmp/test_socket"}, [110]) = 4 read(4, "test_msg_12345", 64) = 12 write(1, "Received: test_msg_12345\n", 25) = 25 read(4, "test_msg_12345", 64) = 12 write(1, "Received: test_msg_12345\n", 25) = 25 # 持续重复上述read和write操作
内容的提问来源于stack exchange,提问作者RootPhoenix
相关产品推荐
相关产品推荐

