LocalSocket
是基于 Unix 域套接字(Unix Domain Socket)的 IPC 机制,用于同一设备上的进程间通信。它通过内核直接传递数据,绕过网络协议栈,具有高效率和低延迟的特点,广泛应用于 Android 系统(如与 Zygote 通信)或本地服务通信。
LocalSocket
利用 Unix 域套接字,通过内核在进程间传递数据,其核心在于高效的本地通信机制。以下是详细的工作原理:
/tmp/mysocket
)或抽象命名空间(Linux 的 @socket_name
)定义通信端点。地址由 sockaddr_un
结构体指定,包含地址族(AF_UNIX
)和路径。socket(AF_UNIX, SOCK_STREAM, 0)
创建流式套接字。bind
将套接字绑定到指定路径或命名空间。listen
设置最大连接队列。accept
建立与客户端的连接,返回新的文件描述符。send
和 recv
读写数据。connect
)。send
和 recv
与服务器交换数据。send
/recv
)在缓冲区中直接复制,效率高于网络套接字(因无需 TCP/IP 协议栈)。SOCK_STREAM
)保证数据有序、可靠;数据报模式(SOCK_DGRAM
)则提供无连接的快速传输。sendmsg
和 recvmsg
,可以传递文件描述符(如打开的文件、设备或套接字),实现高效资源共享。chmod
)和 SELinux 策略约束,仅允许授权进程访问。@
开头)不依赖文件系统,权限由内核命名空间管理,适合高安全性场景。select
/poll
等机制。SOCK_DGRAM
)不可靠,可能丢失数据。以下是一个优化的 C++ 示例,展示服务器和客户端通过 LocalSocket
通信。代码增强了错误处理、日志记录,并确保缓冲区安全。
#include
#include
#include
#include
#include
#include
#define SOCKET_PATH "/tmp/mysocket"
#define LOG_ERROR(msg) std::cerr << msg << ": " << strerror(errno) << std::endl
#define BUFFER_SIZE 1024
int main() {
// 创建套接字
int server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (server_fd == -1) {
LOG_ERROR("Socket creation failed");
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);
unlink(SOCKET_PATH); // 清理旧文件
// 绑定
if (bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
LOG_ERROR("Bind failed");
close(server_fd);
return 1;
}
// 监听
if (listen(server_fd, 5) == -1) {
LOG_ERROR("Listen failed");
close(server_fd);
return 1;
}
std::cout << "Server listening on " << SOCKET_PATH << std::endl;
// 接受连接
int client_fd = accept(server_fd, nullptr, nullptr);
if (client_fd == -1) {
LOG_ERROR("Accept failed");
close(server_fd);
return 1;
}
// 通信
char buffer[BUFFER_SIZE] = {0};
ssize_t bytes_received = recv(client_fd, buffer, BUFFER_SIZE - 1, 0);
if (bytes_received == -1) {
LOG_ERROR("Receive failed");
} else if (bytes_received > 0) {
buffer[bytes_received] = '\0';
std::cout << "Received: " << buffer << std::endl;
const char* response = "Hello from server!";
if (send(client_fd, response, strlen(response), 0) == -1) {
LOG_ERROR("Send failed");
}
}
// 清理
close(client_fd);
close(server_fd);
unlink(SOCKET_PATH);
return 0;
}
#include
#include
#include
#include
#include
#include
#define SOCKET_PATH "/tmp/mysocket"
#define LOG_ERROR(msg) std::cerr << msg << ": " << strerror(errno) << std::endl
#define BUFFER_SIZE 1024
int main() {
// 创建套接字
int client_fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (client_fd == -1) {
LOG_ERROR("Socket creation failed");
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);
// 连接服务器
if (connect(client_fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
LOG_ERROR("Connect failed");
close(client_fd);
return 1;
}
// 发送消息
const char* message = "Hello from client!";
if (send(client_fd, message, strlen(message), 0) == -1) {
LOG_ERROR("Send failed");
close(client_fd);
return 1;
}
// 接收响应
char buffer[BUFFER_SIZE] = {0};
ssize_t bytes_received = recv(client_fd, buffer, BUFFER_SIZE - 1, 0);
if (bytes_received == -1) {
LOG_ERROR("Receive failed");
} else if (bytes_received > 0) {
buffer[bytes_received] = '\0';
std::cout << "Received: " << buffer << std::endl;
}
// 清理
close(client_fd);
return 0;
}
g++ -o server server.cpp
g++ -o client client.cpp
./server
./client
Server listening on /tmp/mysocket
和 Received: Hello from client!
Received: Hello from server!
@socket_name
)以避免文件系统依赖。unlink
删除套接字文件,防止绑定冲突。select
、poll
或多线程。sendmsg
和 recvmsg
实现文件或资源共享。fcntl
设置非阻塞模式,结合 select
或 epoll
处理高并发。@
开头的地址,避免文件系统权限问题。