池州网站seo,孟州网站,上海正规网站建设,谷歌浏览器下载目录 一.什么是UNIX域套接字#xff1f; 二.如何使用UNIX域函数进行套接字编程#xff1f;
三.利用socketpair函数进行文件描述符传递 3.1 socketpair函数
3.2 实例
3.3 补充消息结构知识 一.什么是UNIX域套接字#xff1f; Unix域套接字#xff08;Unix Domain Socke…目录 一.什么是UNIX域套接字 二.如何使用UNIX域函数进行套接字编程
三.利用socketpair函数进行文件描述符传递 3.1 socketpair函数
3.2 实例
3.3 补充消息结构知识 一.什么是UNIX域套接字 Unix域套接字Unix Domain Sockets也称为本地套接字Local Sockets是一种特殊的套接字它允许在同一台主机上的进程间进行通信。与网络套接字不同Unix域套接字不经过网络协议栈因此它们通常比网络套接字更快并且不需要端口和IP地址。 Unix域套接字提供了流式SOCK_STREAM和数据报SOCK_DGRAM两种通信方式类似于TCP和UDP。流式套接字提供了可靠的双向字节流通信而数据报套接字则提供了不可靠的双向数据报通信。 二.如何使用UNIX域函数进行套接字编程 2.1 UNIX域的地址结构是 sockaddr_un它用于指定UNIX域套接字的地址。这个结构体通常定义在 sys/un.h 头文件中其基本形式如下
struct sockaddr_un {sa_family_t sun_family; /* Address family (AF_UNIX) */char sun_path[108]; /* Path name */
};sun_family地址家族对于UNIX域套接字这个字段总是设置为 AF_UNIX。sun_path一个字符数组用于存放套接字的路径名。在UNIX域套接字中这个路径名对应于文件系统中的一个节点类似于网络套接字中的IP地址和端口号。 2.2UNIX域套接字的函数与普通的网络套接字函数类似但是它们用于本地通信而不是网络通信。下面是一些常用的UNIX域套接字函数
socket()创建一个新的套接字与普通套接字函数相同但是地址家族参数指定为 AF_UNIX。bind()将套接字绑定到一个特定的地址上对于UNIX域套接字这个地址是一个文件系统路径。listen()允许套接字接受来自其他套接字的连接请求。accept()接受一个传入的连接请求返回一个新的套接字文件描述符用于与连接的客户端通信。connect()发起一个连接到指定地址的套接字。send()、sendto()、sendmsg()用于发送数据。recv()、recvfrom()、recvmsg()用于接收数据。close()关闭套接字连接。 2.3UNIX域套接字函数与普通套接字函数的主要区别在于地址结构和地址家族。UNIX域套接字使用 sockaddr_un 地址结构而普通套接字使用 sockaddr_in 或 sockaddr_in6 地址结构。此外UNIX域套接字的地址是一个文件系统路径而不是IP地址和端口号。
UNIX域套接字的优点包括
本地通信速度更快因为不需要经过网络协议栈。不受网络配置的影响不需要IP地址和端口号。提供了流式SOCK_STREAM和数据报SOCK_DGRAM两种通信方式。 UNIX域套接字的缺点包括
只能在同一台主机上的进程间通信。需要管理套接字文件这可能会带来一些复杂性。 2.4一个简单实例
服务端代码
#include stdio.h
#include stdlib.h
#include string.h
#include sys/socket.h
#include sys/un.h
#include unistd.h#define SOCKET_PATH /tmp/uds_socket
#define BUFFER_SIZE 1024int main() {int server_fd, client_fd;struct sockaddr_un server_addr, client_addr;socklen_t client_addr_len;char buffer[BUFFER_SIZE];// 创建 Unix 域套接字server_fd socket(AF_UNIX, SOCK_STREAM, 0);if (server_fd -1) {perror(socket);exit(EXIT_FAILURE);}// 初始化服务器地址结构memset(server_addr, 0, sizeof(server_addr));server_addr.sun_family AF_UNIX;strncpy(server_addr.sun_path, SOCKET_PATH, sizeof(server_addr.sun_path) - 1);// 绑定套接字到地址if (bind(server_fd, (struct sockaddr *)server_addr, sizeof(server_addr)) -1) {perror(bind);exit(EXIT_FAILURE);}// 监听套接字if (listen(server_fd, 1) -1) {perror(listen);exit(EXIT_FAILURE);}// 接受客户端连接client_addr_len sizeof(client_addr);client_fd accept(server_fd, (struct sockaddr *)client_addr, client_addr_len);if (client_fd -1) {perror(accept);exit(EXIT_FAILURE);}// 读取客户端发送的数据if (read(client_fd, buffer, BUFFER_SIZE) -1) {perror(read);exit(EXIT_FAILURE);}printf(Received message: %s\n, buffer);// 关闭套接字close(client_fd);close(server_fd);// 删除 Unix 域套接字文件unlink(SOCKET_PATH);return 0;
}客户端代码
#include stdio.h
#include stdlib.h
#include string.h
#include sys/socket.h
#include sys/un.h
#include unistd.h#define SOCKET_PATH /tmp/uds_socket
#define BUFFER_SIZE 1024int main() {int client_fd;struct sockaddr_un server_addr;char buffer[BUFFER_SIZE] Hello, Server!;// 创建 Unix 域套接字client_fd socket(AF_UNIX, SOCK_STREAM, 0);if (client_fd -1) {perror(socket);exit(EXIT_FAILURE);}// 初始化服务器地址结构memset(server_addr, 0, sizeof(server_addr));server_addr.sun_family AF_UNIX;strncpy(server_addr.sun_path, SOCKET_PATH, sizeof(server_addr.sun_path) - 1);// 连接到服务器if (connect(client_fd, (struct sockaddr *)server_addr, sizeof(server_addr)) -1) {perror(connect);exit(EXIT_FAILURE);}// 发送数据到服务器if (write(client_fd, buffer, strlen(buffer) 1) -1) {perror(write);exit(EXIT_FAILURE);}// 关闭套接字close(client_fd);return 0;
}这个过程非常类似网络通信但这仅仅是一个主机内的不同进程间通信大家需要弄清楚原理 三.利用socketpair函数进行文件描述符传递 3.1 socketpair函数
在Unix系统中socketpair 函数用于创建一对无连接的套接字这两个套接字可以用于本地进程间的通信。这个函数创建的套接字对类似于管道pipe但提供了全双工通信的能力即两个进程都可以同时进行发送和接收操作。 注意socketpair 函数创建的套接字对专门用于本地进程间通信它们不能用于网络通信。这些套接字是基于 Unix 域AF_UNIX的这意味着它们只在同一台主机上的进程之间提供通信能力。Unix域套接字不涉及网络协议栈因此它们不受网络接口、IP 地址、端口等网络概念的影响。 如果你需要在不同主机上的进程之间进行通信你应该使用网络套接字这通常是基于 AF_INETIPv4或 AF_INET6IPv6地址族的。网络套接字允许进程通过 TCP 或 UDP 协议在网络中进行通信并且可以通过指定目标 IP 地址和端口号来建立连接。 int socketpair(int domain, int type, int protocol, int sv[2]);domain指定套接字域通常为 AF_UNIX表示本地通信。type指定套接字类型可以是 SOCK_STREAM流式套接字或 SOCK_DGRAM数据报套接字。protocol通常设置为0让系统自动选择协议。sv一个包含两个整数的数组用于接收创建的套接字文件描述符。 socketpair 函数成功时返回0失败时返回-1并设置errno来表示错误。
3.2 实例 要使用 socketpair 函数给两个不同进程传递 msghdr 消息我们可以利用 socketpair 创建的套接字对来进行进程间通信。下面是一个示例代码展示了如何在一个进程中创建 msghdr 消息然后通过 socketpair 传递给另一个进程
#include stdio.h
#include stdlib.h
#include string.h
#include sys/socket.h
#include unistd.h
#include sys/types.h
#include sys/wait.h#define BUF_SIZE 1024int main(int argc, char *argv[]) {int sock_pair[2];struct msghdr msg;struct iovec iov;char buf[BUF_SIZE];pid_t pid;// 创建 socketpairif (socketpair(AF_UNIX, SOCK_STREAM, 0, sock_pair) 0) {perror(socketpair);exit(EXIT_FAILURE);}pid fork();if (pid 0) { // 子进程close(sock_pair[0]); // 关闭不需要的套接字// 接收消息memset(msg, 0, sizeof(msg));iov.iov_base buf;iov.iov_len BUF_SIZE;msg.msg_iov iov;msg.msg_iovlen 1;if (recvmsg(sock_pair[1], msg, 0) 0) {perror(recvmsg);exit(EXIT_FAILURE);}printf(Child received: %s\n, buf);close(sock_pair[1]);} else if (pid 0) { // 父进程close(sock_pair[1]); // 关闭不需要的套接字// 准备发送消息strcpy(buf, Hello, child process!);iov.iov_base buf;iov.iov_len strlen(buf) 1;msg.msg_iov iov;msg.msg_iovlen 1;// 发送消息if (sendmsg(sock_pair[0], msg, 0) 0) {perror(sendmsg);exit(EXIT_FAILURE);}close(sock_pair[0]);wait(NULL); // 等待子进程结束} else {perror(fork);exit(EXIT_FAILURE);}return 0;
}在这个例子中父进程通过 socketpair 创建了一对套接字然后通过 fork 创建了一个子进程。父子进程各自关闭了自己不需要的套接字文件描述符然后使用剩下的套接字进行通信。父进程准备了一个 msghdr 消息并通过 sendmsg 发送给子进程子进程通过 recvmsg 接收并打印接收到的消息。 这个例子展示了如何使用 socketpair 和 msghdr 在两个进程间传递消息。这种通信方式适用于本地进程间的高效通信不需要经过网络协议栈因此在性能上比网络通信更优。 3.3 补充消息结构知识
在Unix网络编程中msghdr 结构体是用来在进程和内核之间传递消息的控制信息。这个结构体在 sys/socket.h 头文件中定义用于 sendmsg 和 recvmsg 系统调用这两个调用可以处理带外数据、多个数据缓冲区以及控制信息。
msghdr 结构体的定义可能因不同的Unix系统和版本而有所不同但通常包含以下字段
msg_name指向接收者或发送者的地址的指针。msg_namelen地址的长度。msg_iov一个 iovec 结构数组用于指定数据缓冲区。msg_iovlenmsg_iov 数组中的元素个数。msg_control指向辅助数据的指针通常用于传递Ancillary Data如文件描述符、凭证等。msg_controllen辅助数据的长度。msg_flags指定接收或发送时的消息标志例如 MSG_OOB 表示带外数据。
这里是一个简化的 msghdr 结构体的示例
struct msghdr {void *msg_name; /* Optional address */socklen_t msg_namelen; /* Size of address */struct iovec *msg_iov; /* Scatter/gather array */int msg_iovlen; /* # elements in msg_iov */void *msg_control; /* Ancillary data, see below */socklen_t msg_controllen; /* Ancillary data buffer len */int msg_flags; /* Flags on received message */
};而cmsghdr 是在 Unix 网络编程中用于处理辅助数据ancillary data的结构体。辅助数据是一种特殊的通信数据它不直接包含在正常的数据流中而是与正常数据一起通过 sendmsg 和 recvmsg 系统调用发送和接收。辅助数据可以用于传递控制信息如文件描述符、证书、流量控制信息等。
cmsghdr 结构体通常定义在 sys/socket.h 头文件中它的字段包括
cmsg_len表示整个 cmsghdr 结构体加上随后的数据的长度。cmsg_level指定协议级别通常是 SOL_SOCKET表示通用套接字选项也可以是其他协议级别。cmsg_type指定辅助数据的类型例如 SCM_RIGHTS 用于传递文件描述符。
struct cmsghdr {socklen_t cmsg_len; /* Data byte count, including the cmsghdr */int cmsg_level; /* Originating protocol */int cmsg_type; /* Protocol-specific type */
/* followed byunsigned char cmsg_data[]; */
};在发送和接收辅助数据时msg_control 字段指向一个缓冲区这个缓冲区包含了一个或多个 cmsghdr 结构体每个结构体后面跟着相应的数据。msg_controllen 字段指定了整个控制消息缓冲区的大小。 使用 cmsghdr 需要注意正确计算 cmsg_len以及在发送和接收时正确处理对齐问题因为 cmsg_data 部分可能需要特定于平台的对齐。在 Linux 上可以使用 CMSG_FIRSTHDR、CMSG_NXTHDR、CMSG_DATA 等宏来帮助处理这些细节。