起因
最近在看ceph的动态参数修改。就观察到了Unix Domain Socket这个技术。
那这个UDS具体是个啥呢?
Unix Domain Socket(UDS) 是一种 在同一台计算机上的不同进程之间进行通信的机制。你可以把它理解为"本地版的网络套接字",但它不走网络,只在操作系统内部完成数据交换。
一个例子
假定我有个c++程序,里面有个变量,我现在想修改它怎么办?
简单说一个c++每隔几秒钟打印一个字符串,这个字符串就存在进程的内存里,并不是从磁盘里实时读取的。现在想让程序打印另一个字符串怎么办?
来看代码:
服务端代码
cpp
// server.cpp
#include <iostream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <fcntl.h>
#include <signal.h>
const char* SOCKET_PATH = "/tmp/uds_example.sock";
// 全局变量,被循环输出
std::string message = "Hello from C++ server!";
// 清理 socket 文件
void cleanup() {
unlink(SOCKET_PATH);
std::cout << "\n[Server] Shutdown: socket cleaned up.\n";
}
// 信号处理(Ctrl+C)
void sigint_handler(int sig) {
cleanup();
exit(0);
}
int main() {
int server_fd, client_fd;
struct sockaddr_un addr;
socklen_t len;
// 注册信号处理
signal(SIGINT, sigint_handler);
// 创建 UDS socket
server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (server_fd == -1) {
perror("[Server] socket");
return 1;
}
// 绑定地址
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, SOCKET_PATH, sizeof(addr.sun_path) - 1);
// 删除旧 socket(如果存在)
unlink(SOCKET_PATH);
if (bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
perror("[Server] bind");
close(server_fd);
return 1;
}
if (listen(server_fd, 1) == -1) {
perror("[Server] listen");
close(server_fd);
return 1;
}
std::cout << "[Server] Listening on " << SOCKET_PATH << std::endl;
std::cout << "[Server] Initial message: \"" << message << "\"" << std::endl;
std::cout << "[Server] Waiting for client..." << std::endl;
// 正确设置非阻塞模式
int flags = fcntl(server_fd, F_GETFL, 0); // 先获取原有标志
if (flags == -1) {
perror("fcntl getfl");
close(server_fd);
return 1;
}
fcntl(server_fd, F_SETFL, flags | O_NONBLOCK); // 再加上 O_NONBLOCK
while (true) {
// 尝试接受连接(非阻塞)
client_fd = accept(server_fd, (struct sockaddr*)&addr, &len);
if (client_fd != -1) {
char buffer[1024];
ssize_t bytes = recv(client_fd, buffer, sizeof(buffer) - 1, 0);
if (bytes > 0) {
buffer[bytes] = '\0';
std::cout << "\n[Server] Received from client: \"" << buffer << "\"" << std::endl;
message = buffer; // 更新全局变量
}
if (config.message=="shutdown"){
std::cout << "[Server] i get shutdown command" << std::endl;
break;
}
close(client_fd);
} else if (errno != EAGAIN && errno != EWOULDBLOCK) {
// 真正的错误
if (errno != EINTR) {
usleep(100000); // 短暂休眠避免忙等
}
}
// 持续输出当前消息
std::cout << "[Server] Current message: \"" << message << "\"" << std::endl;
usleep(500000); // sleep 0.5s
}
close(server_fd);
cleanup();
return 0;
}
client端代码
cpp
// client.cpp
#include <iostream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
const char* SOCKET_PATH = "/tmp/uds_example.sock";
int main(int argc, char* argv[]) {
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << " <new_message>\n";
std::cerr << "Example: " << argv[0] << " \"Hello World!\"\n";
return 1;
}
std::string message = argv[1];
int sockfd;
struct sockaddr_un addr;
// 创建 UDS socket
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sockfd == -1) {
perror("[Client] socket");
return 1;
}
// 设置地址
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, SOCKET_PATH, sizeof(addr.sun_path) - 1);
// 连接服务端
if (connect(sockfd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
perror("[Client] connect");
std::cerr << "[Client] Is the server running?\n";
close(sockfd);
return 1;
}
// 发送消息
if (send(sockfd, message.c_str(), message.length(), 0) == -1) {
perror("[Client] send");
close(sockfd);
return 1;
}
std::cout << "[Client] Sent: \"" << message << "\"\n";
close(sockfd);
return 0;
}
大家试试呗