营销型网站建设熊掌号在线优化seo
简述
在Linux中,socketpair
函数可以用于创建一对相互连接的、通信域为AF_UNIX
的套接字,其中一个套接字可用于读取,另一个套接字可用于写入。可以使用这对套接字在同一进程内进行进程间通信(IPC)。
以下是使用socketpair
函数创建套接字对的基本步骤:
-
包含头文件
sys/types.h
、sys/socket.h
和unistd.h
。 -
声明一个长度为2的数组作为套接字描述符的参数。
-
调用
socketpair
函数,并将套接字描述符数组作为参数传递给它。函数原型为:int socketpair(int domain, int type, int protocol, int sv[2]);
domain
参数指定通信域,通常设置为AF_UNIX。type
参数指定套接字类型,可以设置为SOCK_STREAM
或SOCK_DGRAM
。protocol
参数通常设置为0,表示使用默认协议。sv
参数是一个长度为2的整数数组,用于保存创建的套接字描述符。
-
使用
sv
数组中的套接字描述符进行进程间通信。
Linux举例
下面是一个基于 socketpair
的简单例子,用于在父子进程之间传递数据:
#include <unistd.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>int main() {int sockfd[2];char buf[1024];pid_t pid;if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd) < 0) {perror("socketpair");return 1;}if ((pid = fork()) == -1) {perror("fork");return 1;}if (pid == 0) { // 子进程close(sockfd[0]);char msg[] = "Hello, parent!";if (write(sockfd[1], msg, strlen(msg)) < 0) {perror("write");return 1;}close(sockfd[1]);} else { // 父进程close(sockfd[1]);int n = read(sockfd[0], buf, sizeof(buf));if (n < 0) {perror("read");return 1;}printf("Parent: received message from child: %s\n", buf);close(sockfd[0]);}return 0;
}
该程序首先调用 socketpair
函数创建一对 UNIX 域套接字,存储在 sockfd
数组中。然后,程序调用 fork
函数创建一个子进程。在子进程中,它关闭 sockfd[0]
,然后将一条消息写入 sockfd[1]
,然后关闭 sockfd[1]
。在父进程中,它关闭 sockfd[1]
,然后从 sockfd[0]
中读取一条消息,并将其打印到标准输出中,最后关闭 sockfd[0]
。
当该程序运行时,它会创建一个子进程,子进程向父进程发送一条消息,父进程接收到该消息并将其打印出来:
Parent: received message from child: Hello, parent!
Android framework 举例
android-12.0.0_r28/frameworks/native/libs/sensor/BitTube.cpp
BitTube
void BitTube::init(size_t rcvbuf, size_t sndbuf) {int sockets[2];if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) == 0) {size_t size = DEFAULT_SOCKET_BUFFER_SIZE;setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf));setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf));// sine we don't use the "return channel", we keep it small...setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));fcntl(sockets[0], F_SETFL, O_NONBLOCK);fcntl(sockets[1], F_SETFL, O_NONBLOCK);mReceiveFd = sockets[0];mSendFd = sockets[1];} else {mReceiveFd = -errno;ALOGE("BitTube: pipe creation failed (%s)", strerror(-mReceiveFd));}
}
BitTube.cpp
是 Android 中传感器服务和传感器驱动程序之间通信使用的 BitTube
类的实现文件。
InputTransport
android-12.0.0_r28/frameworks/native/libs/input/InputTransport.cpp
status_t InputChannel::openInputChannelPair(const std::string& name,std::unique_ptr<InputChannel>& outServerChannel,std::unique_ptr<InputChannel>& outClientChannel) {int sockets[2];if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {status_t result = -errno;ALOGE("channel '%s' ~ Could not create socket pair. errno=%s(%d)", name.c_str(),strerror(errno), errno);outServerChannel.reset();outClientChannel.reset();return result;}int bufferSize = SOCKET_BUFFER_SIZE;setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));sp<IBinder> token = new BBinder();std::string serverChannelName = name + " (server)";android::base::unique_fd serverFd(sockets[0]);outServerChannel = InputChannel::create(serverChannelName, std::move(serverFd), token);std::string clientChannelName = name + " (client)";android::base::unique_fd clientFd(sockets[1]);outClientChannel = InputChannel::create(clientChannelName, std::move(clientFd), token);return OK;
}
在 Android Input 系统中,InputTransport
使用 socketpair
函数创建一对全双工的本地套接字(socket),用于在应用程序和驱动程序之间传递输入事件。其中一个套接字用于向驱动程序发送输入事件,另一个套接字用于接收来自驱动程序的输入事件。通过这种方式,InputTransport
可以将输入事件发送到驱动程序,并接收驱动程序生成的输入事件。