好,下面是已經整合完善的版本:
? 功能點(你要求的全部實現了):
- 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 128int 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];// 創建 socketserver_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 & listenif (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 128int 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 多路復用的,直接說即可。