好,下面是已经整合完善的版本:
✅ 功能点(你要求的全部实现了):
- Unix Domain Socket (
SOCK_STREAM
) - 服务端先启动:正常通信
- 客户端先启动:等待服务端直到连接成功
- 客户端每秒发送一条消息
- 服务端收到后打印并原样回传
- 服务端断开后,客户端自动重连继续通信
- 稳定循环运行
📁 项目结构
unix_socket_loop/
├── server.c
└── client.c
✅ server.c(服务端)
// server.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <signal.h>
#define SOCKET_PATH "/tmp/mysocket"
#define BUFFER_SIZE 128
int server_fd = -1;
void cleanup() {
if (server_fd != -1) close(server_fd);
unlink(SOCKET_PATH);
printf("Server cleanup done.\n");
exit(0);
}
int main() {
signal(SIGINT, cleanup); // Ctrl+C 退出时清理
struct sockaddr_un addr;
char buffer[BUFFER_SIZE];
// 创建 socket
server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (server_fd == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
unlink(SOCKET_PATH); // 清除旧 socket 文件
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, SOCKET_PATH, sizeof(addr.sun_path) - 1);
// bind & listen
if (bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
perror("bind");
exit(EXIT_FAILURE);
}
if (listen(server_fd, 5) == -1) {
perror("listen");
exit(EXIT_FAILURE);
}
printf("Server is listening at %s ...\n", SOCKET_PATH);
while (1) {
int client_fd = accept(server_fd, NULL, NULL);
if (client_fd == -1) {
perror("accept");
continue;
}
printf("Client connected.\n");
while (1) {
memset(buffer, 0, BUFFER_SIZE);
ssize_t len = read(client_fd, buffer, BUFFER_SIZE - 1);
if (len <= 0) {
printf("Client disconnected.\n");
close(client_fd);
break;
}
printf("Server received: %s\n", buffer);
write(client_fd, buffer, strlen(buffer)); // 回传
}
}
cleanup();
}
✅ client.c(客户端)
// client.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <errno.h>
#define SOCKET_PATH "/tmp/mysocket"
#define BUFFER_SIZE 128
int connect_to_server() {
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd == -1) {
perror("socket");
return -1;
}
struct sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, SOCKET_PATH, sizeof(addr.sun_path) - 1);
while (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
printf("Waiting for server... (%s)\n", strerror(errno));
sleep(1);
}
printf("Connected to server.\n");
return fd;
}
int main() {
char buffer[BUFFER_SIZE];
int counter = 0;
int client_fd = connect_to_server();
if (client_fd < 0) {
fprintf(stderr, "Failed to connect.\n");
return EXIT_FAILURE;
}
while (1) {
snprintf(buffer, BUFFER_SIZE, "Hello %d", counter++);
if (write(client_fd, buffer, strlen(buffer)) == -1) {
perror("write");
close(client_fd);
printf("Connection lost. Reconnecting...\n");
client_fd = connect_to_server();
continue;
}
memset(buffer, 0, BUFFER_SIZE);
ssize_t len = read(client_fd, buffer, BUFFER_SIZE - 1);
if (len <= 0) {
printf("Server disconnected. Reconnecting...\n");
close(client_fd);
client_fd = connect_to_server();
continue;
}
printf("Client received: %s\n", buffer);
sleep(1);
}
close(client_fd);
return 0;
}
✅ 编译和运行
gcc server.c -o server
gcc client.c -o client
运行服务端(终端1):
./server
可以先或后运行客户端(终端2):
./client
✅ 测试行为
测试行为 | 结果 |
---|---|
先运行 client | 等待 server 启动后自动连接 |
server 崩溃后重新启动 | client 会自动重连继续发数据 |
server 收到后打印并回传 | 正常 |
client 每秒发送一条数据 | 正常 |
✅ 下一步推荐扩展(可选):
- 多客户端并发支持(server 用
fork
或select
) - 消息使用 TLV 或 JSON
- 增加超时处理或心跳机制
- 加日志输出和守护进程运行
如需我帮你扩展支持多客户端并发或改成 select 多路复用的,直接说即可。