当前位置: 首页 > news >正文

温州做外贸网站海淘手表网站

温州做外贸网站,海淘手表网站,沈阳新闻今天头条新闻,做外贸网站特色我们的目的是#xff0c;实现进程间传递文件描述符#xff0c;是指 A进程打开文件fileA,获得文件描述符为fdA#xff0c;现在 A进程要通过某种方法#xff0c;传递fdA#xff0c;使得另一个进程B#xff0c;获得一个新的文件描述符fdB#xff0c;这个fdB在进程B中的作用…        我们的目的是实现进程间传递文件描述符是指 A进程打开文件fileA,获得文件描述符为fdA现在 A进程要通过某种方法传递fdA使得另一个进程B获得一个新的文件描述符fdB这个fdB在进程B中的作用跟fdA在进程A中的作用一样。即在 fdB上的操作即是对fileA的操作。 可能很多人想到的是用管道pipe来实现但是却没想象的那么容易。 1.了解fork函数 首先需要知道在调用 fork() 函数之前打开的文件其文件描述符会被复制到子进程中。这是因为在 fork() 函数执行时操作系统会创建子进程而子进程将复制父进程的地址空间包括文件描述符表。因此父进程打开的文件描述符会被子进程继承并复制到子进程的文件描述符表中。 #include stdio.h #include stdlib.h #include unistd.h #include fcntl.h #include sys/wait.hint main() {int file_fd;pid_t pid;char buf[1024];// 打开文件file_fd open(file.txt, O_RDONLY);if (file_fd -1) {perror(open);exit(EXIT_FAILURE);}// 创建子进程pid fork();if (pid -1) {perror(fork);exit(EXIT_FAILURE);}if (pid 0) {// 子进程ssize_t num_read;// 使用父进程打开的文件描述符操作文件while ((num_read read(file_fd, buf, sizeof(buf))) 0) {write(STDOUT_FILENO, buf, num_read);}if (num_read -1) {perror(read);exit(EXIT_FAILURE);}close(file_fd); // 关闭文件描述符_exit(EXIT_SUCCESS); // 退出子进程} else {// 父进程int status;// 等待子进程结束wait(status);// 关闭文件描述符close(file_fd);if (WIFEXITED(status)) {printf(子进程正常退出退出状态码%d\n, WEXITSTATUS(status));} else if (WIFSIGNALED(status)) {printf(子进程异常终止信号编号%d\n, WTERMSIG(status));}}return 0; }其次在父进程调用 fork() 函数之后打开的文件子进程不会自动继承这些新打开的文件描述符。也就是说父进程在 fork() 之后打开的文件描述符只在父进程的文件描述符表中有效子进程不会获得这些文件描述符。 #include stdio.h #include stdlib.h #include unistd.h #include fcntl.h #include sys/wait.hint main() {int file_fd;pid_t pid;char buf[1024];// 创建子进程pid fork();if (pid -1) {perror(fork);exit(EXIT_FAILURE);}if (pid 0) {// 子进程printf(子进程开始...\n);// 尝试读取父进程在fork之后打开的文件描述符这里没有实际的文件描述符所以操作会失败ssize_t num_read read(3, buf, sizeof(buf)); // 假设文件描述符3是父进程在fork之后打开的if (num_read -1) {perror(子进程无法读取文件因为没有继承父进程在fork之后打开的文件描述符);} else {write(STDOUT_FILENO, buf, num_read);}_exit(EXIT_SUCCESS); // 退出子进程} else {// 父进程int status;// 在fork之后打开文件file_fd open(file.txt, O_RDONLY);if (file_fd -1) {perror(open);exit(EXIT_FAILURE);}printf(父进程打开的文件描述符: %d\n, file_fd);// 等待子进程结束wait(status);// 关闭文件描述符close(file_fd);if (WIFEXITED(status)) {printf(子进程正常退出退出状态码%d\n, WEXITSTATUS(status));} else if (WIFSIGNALED(status)) {printf(子进程异常终止信号编号%d\n, WTERMSIG(status));}}return 0; }结论 在 fork() 之前打开的文件描述符子进程会继承并可以使用。在 fork() 之后打开的文件描述符子进程不会继承无法直接使用这些文件描述符。 2.使用管道pipe传递文件描述符的问题 下面是使用管道pipe传递文件描述符的示例代码 #include stdio.h #include stdlib.h #include unistd.h #include fcntl.h #include sys/wait.h#define BUF_SIZE 1024int main() {int pipe_fd[2]; // 管道的文件描述符数组int file_fd; // 文件的文件描述符pid_t pid;char buf[BUF_SIZE];// 创建管道if (pipe(pipe_fd) -1) {perror(pipe);exit(EXIT_FAILURE);}// 创建子进程pid fork();if (pid -1) {perror(fork);exit(EXIT_FAILURE);}if (pid 0) {// 子进程close(pipe_fd[1]); // 关闭子进程不需要的写入端// 从管道中读取父进程传递的文件描述符int received_fd;read(pipe_fd[0], received_fd, sizeof(int));printf(received_fd:%d\n, received_fd);// 使用接收到的文件描述符操作文件Assize_t num_read;while ((num_read read(received_fd, buf, BUF_SIZE)) 0) {write(STDOUT_FILENO, buf, num_read); // 在子进程中输出文件内容}if (num_read -1) {perror(read);exit(EXIT_FAILURE);}close(received_fd); // 关闭文件描述符close(pipe_fd[0]); // 关闭管道读取端_exit(EXIT_SUCCESS); // 退出子进程} else {// 父进程close(pipe_fd[0]); // 关闭父进程不需要的读取端// 打开文件A并获取文件描述符file_fd open(fileA.txt, O_RDONLY);if (file_fd -1) {perror(open);exit(EXIT_FAILURE);}printf(file_fd:%d\n, file_fd);// 将文件描述符写入管道传递给子进程if (write(pipe_fd[1], file_fd, sizeof(int)) ! sizeof(int)) {perror(write);exit(EXIT_FAILURE);}close(file_fd); // 关闭父进程中的文件描述符close(pipe_fd[1]); // 关闭管道写入端wait(NULL); // 等待子进程结束exit(EXIT_SUCCESS); // 退出父进程} }失败的原因在代码中父进程使用 write(pipe_fd[1], file_fd, sizeof(int)) 将 file_fd 写入管道的写入端。这一步骤本质上是将一个整数文件描述符写入到管道中。在Unix-like系统中文件描述符是进程特定的它们不能简单地通过整数值在不同的进程之间传递。直接通过管道传递文件描述符的整数值是无效的因为文件描述符是相对于进程的。 要正确地传递文件描述符必须使用sendmsg和recvmsg系统调用以及SCM_RIGHTS控制消息。这些系统调用允许在进程间传递文件描述符而不仅仅是它们的整数值。 3.相关操作函数 3.1socketpair 函数 socketpair 函数用于在本地创建一对连接的套接字通常用于同一主机上的进程间通信。它创建了一个双向通道使得两个相关联的套接字可以在两个进程之间传递数据实现全双工通信。socketpair 通常用于需要在同一台主机上的不同进程之间进行高效通信的场景。例如父子进程间或者同一程序的不同线程之间。 #include sys/types.h #include sys/socket.h int socketpair(int domain, int type, int protocol, int sv[2]); 参数详解 domain指定套接字的协议族通常为 AF_UNIXUnix 域套接字用于本地进程间通信。 type指定套接字的类型常见的有SOCK_STREAM提供面向连接的、可靠的数据传输服务如 TCP。SOCK_DGRAM提供无连接、不可靠的数据传输服务如 UDP。 protocol指定套接字使用的协议一般为 0表示使用默认协议。 sv[2]一个整型数组用于存放创建的套接字对的文件描述符。在调用 socketpair 函数后sv[0] 和 sv[1] 分别包含这两个相关联的套接字的文件描述符。 返回值 成功时返回 0。 失败时返回 -1并设置 errno 指示错误的类型。 3.2 sendmsg函数 sendmsg 函数用于向指定套接字发送消息支持发送多块数据和控制消息例如文件描述符。 #include sys/socket.h ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); 参数详解 sockfd指定发送消息的套接字描述符。 msg 指向 struct msghdr 结构体的指针描述了要发送的消息的详细信息包括数据块 (iovec 结构体数组) 和控制消息 (cmsghdr 结构体)。 flags通常为 0用于控制消息发送的附加选项。 返回值 成功时返回发送的字节数。 失败时返回 -1并设置 errno 指示错误的类型。 3.3 recvmsg函数 recvmsg 函数用于从指定套接字接收消息支持接收多块数据和控制消息例如文件描述符。 #include sys/socket.h ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags); 参数详解 sockfd指定接收消息的套接字描述符。 msg 指向 struct msghdr 结构体的指针用于存放接收到的消息的详细信息包括数据块 (iovec 结构体数组) 和控制消息 (cmsghdr 结构体)。 flags通常为 0用于控制消息接收的附加选项。 返回值 成功时返回发送的字节数。 失败时返回 -1并设置 errno 指示错误的类型。 3.4 struct msghdr 结构体详解 struct msghdr {void *msg_name; // 指向目标地址的指针socklen_t msg_namelen; // 目标地址的长度struct iovec *msg_iov; // 数据块的数组size_t msg_iovlen; // 数据块数组的长度void *msg_control; // 控制消息的指针size_t msg_controllen; // 控制消息的长度int msg_flags; // 消息的标志 }; 结构体成员msg_name 和 msg_namelen用于指定目标地址的信息通常用于 UDP 套接字。msg_iov 和 msg_iovlen用于指定数据块的数组和数组长度支持数据的分散/聚集操作。msg_control 和 msg_controllen用于处理控制消息如文件描述符的指针和长度。msg_flags用于指定消息的标志例如 MSG_DONTWAIT 等。struct iovec {void *iov_base; // 指向数据缓冲区的指针size_t iov_len; // 数据缓冲区的长度 }; 成员解释iov_base指向数据缓冲区的指针即存放数据的内存地址。iov_len数据缓冲区的长度即缓冲区中可以传输的数据的字节数。工作原理 sendmsg 函数通过 msg 结构体描述要发送的数据块和控制消息。recvmsg 函数从套接字接收数据并将接收到的数据填充到 msg 结构体中指定的缓冲区中。 控制消息传递 sendmsg 和 recvmsg 支持通过 msg_control 和 msg_controllen 参数传递控制消息cmsghdr 结构体特别是用于传递文件描述符等特殊信息。 应用场景 进程间通信IPCsendmsg 和 recvmsg 可以在进程间传递复杂的数据结构和文件描述符适用于需要高效数据传输和资源共享的场景。网络编程在网络编程中这两个函数用于向套接字发送数据和从套接字接收数据支持分散/聚集操作和控制消息传递。 作用 struct iovec 结构体主要用于描述 msg_iov 参数即 struct msghdr 结构体中的数据块数组。它允许用户指定多个数据块的位置和长度从而实现数据的分散scatter和聚集gather操作。 3.5 writev 和 readv 函数 操作 struct iovec 结构体的系统调用主要用于实现数据的分散读scatter和聚集写gather操作这些操作通常用于高效地传输多个数据块。 功能 writev 函数将多个数据块从 iov 指定的缓冲区中写入到文件描述符 fd 所指定的文件中。readv 函数从文件描述符 fd 所指定的文件中读取数据并存储到 iov 指定的多个缓冲区中。 #include sys/uio.h ssize_t writev(int fd, const struct iovec *iov, int iovcnt); ssize_t readv(int fd, const struct iovec *iov, int iovcnt); 参数fd文件描述符表示要读写的文件。iov指向 struct iovec 结构体数组的指针描述要读写的数据块及其位置。iovcntiov 数组中元素的个数即要读写的数据块的数量。 返回值 成功时返回读写的字节数。 失败时返回 -1并设置 errno 指示错误的类型。 工作原理 writev 函数将 iov 数组中描述的多个数据块依次写入到文件描述符 fd 指定的文件中。readv 函数从文件描述符 fd 指定的文件中读取数据并将数据依次存储到 iov 数组中指定的多个缓冲区中。 数据传输 writev 和 readv 函数支持数据的分散scatter和聚集gather操作可以高效地处理多个非连续数据块的读写。 应用场景 在网络编程中writev 和 readv 可以用于同时发送或接收多个数据块提高数据传输的效率。在文件操作中对于需要同时读写多个缓冲区数据的场景如日志文件写入等也可以使用这两个函数。 4.示例代码 将父进程中得到文件描述符传递给子进程子进程得到该文件描述符同样可以操作该文件实现文件描述符在进程间真正的传递。 #include stdio.h #include stdlib.h #include unistd.h #include fcntl.h #include sys/wait.h #include sys/socket.h #include sys/types.h #include sys/uio.hvoid send_fd(int socket, int fd_to_send) {struct msghdr msg {0}; // 定义消息头结构体并初始化struct iovec iov[1]; // 定义数据块结构体数组struct cmsghdr *cmsg; // 定义控制消息头指针char control[CMSG_SPACE(sizeof(int))]; // 控制信息缓冲区char dummy *; // 用于填充数据块的虚拟字符iov[0].iov_base dummy; // 设置数据块的基址为虚拟字符的地址iov[0].iov_len 1; // 设置数据块的长度为1字节msg.msg_iov iov; // 设置消息头的数据块数组msg.msg_iovlen 1; // 设置数据块数组的长度msg.msg_control control; // 设置消息头的控制信息msg.msg_controllen sizeof(control); // 设置控制信息的长度cmsg CMSG_FIRSTHDR(msg); // 获取第一个控制消息头cmsg-cmsg_level SOL_SOCKET; // 设置控制消息级别为套接字级别cmsg-cmsg_type SCM_RIGHTS; // 设置控制消息类型为传递文件描述符cmsg-cmsg_len CMSG_LEN(sizeof(int)); // 设置控制消息长度*((int *) CMSG_DATA(cmsg)) fd_to_send; // 将待发送的文件描述符复制到控制消息的数据部分if (sendmsg(socket, msg, 0) -1) { // 发送消息perror(sendmsg);} }int recv_fd(int socket) {struct msghdr msg {0}; // 定义消息头结构体并初始化struct iovec iov[1]; // 定义数据块结构体数组struct cmsghdr *cmsg; // 定义控制消息头指针char control[CMSG_SPACE(sizeof(int))]; // 控制信息缓冲区char dummy; // 用于填充数据块的虚拟字符iov[0].iov_base dummy; // 设置数据块的基址为虚拟字符的地址iov[0].iov_len 1; // 设置数据块的长度为1字节msg.msg_iov iov; // 设置消息头的数据块数组msg.msg_iovlen 1; // 设置数据块数组的长度msg.msg_control control; // 设置消息头的控制信息msg.msg_controllen sizeof(control); // 设置控制信息的长度if (recvmsg(socket, msg, 0) -1) { // 接收消息perror(recvmsg);return -1;}cmsg CMSG_FIRSTHDR(msg); // 获取第一个控制消息头unsigned char *data CMSG_DATA(cmsg); // 获取控制消息的数据部分int fd *((int *) data); // 提取文件描述符return fd; // 返回接收到的文件描述符 }int main() {int socket_pair[2]; // 套接字对int file_fd; // 文件的文件描述符pid_t pid;char buf[1024];// 创建套接字对if (socketpair(AF_UNIX, SOCK_STREAM, 0, socket_pair) -1) {perror(socketpair);exit(EXIT_FAILURE);}// 创建子进程pid fork();if (pid -1) {perror(fork);exit(EXIT_FAILURE);}if (pid 0) {// 子进程close(socket_pair[1]); // 关闭子进程不需要的写入端// 从套接字中读取父进程传递的文件描述符int received_fd recv_fd(socket_pair[0]);// 使用接收到的文件描述符操作文件Assize_t num_read;while ((num_read read(received_fd, buf, sizeof(buf))) 0) {write(STDOUT_FILENO, buf, num_read); // 在子进程中输出文件内容}if (num_read -1) {perror(read);exit(EXIT_FAILURE);}close(received_fd); // 关闭文件描述符close(socket_pair[0]); // 关闭套接字读取端_exit(EXIT_SUCCESS); // 退出子进程} else {// 父进程close(socket_pair[0]); // 关闭父进程不需要的读取端// 在fork后打开文件并获取文件描述符file_fd open(fileA.txt, O_RDONLY);if (file_fd -1) {perror(open);exit(EXIT_FAILURE);}// 将文件描述符通过套接字传递给子进程send_fd(socket_pair[1], file_fd);close(file_fd); // 关闭父进程中的文件描述符close(socket_pair[1]); // 关闭套接字写入端wait(NULL); // 等待子进程结束exit(EXIT_SUCCESS); // 退出父进程}return 0; }
http://www.laogonggong.com/news/103221.html

相关文章:

  • 西安免费做网站多少钱网络营销是什么样子的
  • 芜湖做公司网站的梵克雅宝为什么那么贵
  • 狮山建网站网站开发项目规划
  • 学风建设网站版块做网站需要的执照
  • 怎么做网站优化 s老域名全部失效请拿笔记好
  • 企业建站程序哪个好邯郸做网站推广找谁
  • 网站搭建吧wordpress 插件 速度
  • 筑建网站首页快速建站学什么
  • 韩国最牛的设计网站电脑做网站怎么解析域名
  • 厦门网站建设案例wordpress站群代
  • 福田我要做网站优化比较好摄影师作品网站有哪些
  • 上海网站建设 缔客超炫网站
  • 做商城网站需要备案什么域名网站技术说明书模板
  • ui设计师是做网站吗建设银行海外分行招聘网站
  • 怎么seo网站推广网站建设一般多少钱网址
  • 糖果网站是李笑来做的吗佛山网站建设怎么办
  • 郑州做茶叶的网站jsp网站开发详解 下载
  • 鞍山做网站公司江门网络科技有限公司
  • 网站栏目做跳转做购物网站多少钱 知乎
  • 无锡网站建设人员wordpress ftp上传插件
  • 江苏网站建设公司哪家好竣工验收报告查询网
  • 诸暨网站制作有哪些公司网站制作编辑软件
  • 怎么攻击网站吗广州网站制作怎么选
  • 手机移动网站建设方案跨境电商平台介绍
  • 网站的验证码是怎么做的毕设做桌面端还是网站
  • 网站备案是针对空间还是域名网站开发周期安排
  • 网站建设管理职责12123互联网服务平台
  • 公司网站维护一般需要做什么下载免费素材库
  • 淘宝网现状 网站建设wordpress自动提取tag
  • 外贸公司网站建设费会计科目线上商城运营的主要工作