前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >进程通信 & PIPE

进程通信 & PIPE

作者头像
changan
发布2020-11-04 15:02:15
7620
发布2020-11-04 15:02:15
举报

历史

UNIX两大贡献者贝尔实验室和BSD,在进程之间通信侧重不同,前者基于内核对进程之间的通信手段进行了改进,形成了“System V IPC”,而后者则是基于网络形成了套接字。

而POSIX则是IEEE制定的标准,目的是为运行在不同操作系统上的软件提供统一的接口,实现者则是不同的操作系统内核开发人员。

System V 以及POSIX 对信号量、共享内存、消息队列等进程之间共享方式提供了自己的解决方案。

在观察使用进程间通信手段后,会发现在多线程中使用的基本是POSIX标准提供的接口函数,而多进程则是基于System V。

管道

pipe和fifo用的不多了,让我们从Nginx那里学一个 全双工的管道: socketpair

image
image
代码语言:javascript
复制
#include <iostream>
#include <unistd.h>
#include <sys/uio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <stdio.h>

ssize_t
sock_fd_write(int sock, void *buf, ssize_t buflen, int fd)
{
  ssize_t     size;
  struct msghdr   msg;
  struct iovec    iov;
  union {
    struct cmsghdr  cmsghdr;
    char        control[CMSG_SPACE(sizeof (int))];
  } cmsgu;
  struct cmsghdr  *cmsg;

  iov.iov_base = buf;
  iov.iov_len = buflen;

  msg.msg_name = NULL;
  msg.msg_namelen = 0;
  msg.msg_iov = &iov;
  msg.msg_iovlen = 1;

  if (fd != -1) {
    msg.msg_control = cmsgu.control;
    msg.msg_controllen = sizeof(cmsgu.control);

    cmsg = CMSG_FIRSTHDR(&msg);
    cmsg->cmsg_len = CMSG_LEN(sizeof (int));
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type = SCM_RIGHTS;

    printf ("passing fd %d\n", fd);
    *((int *) CMSG_DATA(cmsg)) = fd;
  } else {
    msg.msg_control = NULL;
    msg.msg_controllen = 0;
    printf ("not passing fd\n");
  }

  size = sendmsg(sock, &msg, 0);

  if (size < 0)
    perror ("sendmsg");
  return size;
}

ssize_t
sock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd)
{
  ssize_t     size;

  if (fd) {
    struct msghdr   msg;
    struct iovec    iov;
    union {
      struct cmsghdr  cmsghdr;
      char        control[CMSG_SPACE(sizeof (int))];
    } cmsgu;
    struct cmsghdr  *cmsg;

    iov.iov_base = buf;
    iov.iov_len = bufsize;

    msg.msg_name = NULL;
    msg.msg_namelen = 0;
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;
    msg.msg_control = cmsgu.control;
    msg.msg_controllen = sizeof(cmsgu.control);
    size = recvmsg (sock, &msg, 0);
    if (size < 0) {
      perror ("recvmsg");
      exit(1);
    }
    cmsg = CMSG_FIRSTHDR(&msg);
    if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
      if (cmsg->cmsg_level != SOL_SOCKET) {
        fprintf (stderr, "invalid cmsg_level %d\n",
                 cmsg->cmsg_level);
        exit(1);
      }
      if (cmsg->cmsg_type != SCM_RIGHTS) {
        fprintf (stderr, "invalid cmsg_type %d\n",
                 cmsg->cmsg_type);
        exit(1);
      }

      *fd = *((int *) CMSG_DATA(cmsg));
      printf ("received fd %d\n", *fd);
    } else
      *fd = -1;
  } else {
    size = read (sock, buf, bufsize);
    if (size < 0) {
      perror("read");
      exit(1);
    }
  }
  return size;
}

void
child(int sock)
{
  int fd;
  char    buf[16];
  ssize_t size;

  sleep(1);
  for (;;) {
    size = sock_fd_read(sock, buf, sizeof(buf), &fd);
    if (size <= 0)
      break;
    printf ("read %d\n", (int) size);
    if (fd != -1) {
      write(fd, "hello, world\n", 13);
      close(fd);
    }
  }
}

void
parent(int sock)
{
  ssize_t size;
  int i;
  int fd;

  fd = 1;
  size = sock_fd_write(sock, (void *) "1", 1, 1);
  printf ("wrote %d\n", (int) size);
}

int
main(int argc, char **argv)
{
  int sv[2];
  int pid;

  if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sv) < 0) {
    perror("socketpair");
    exit(1);
  }
  switch ((pid = fork())) {
  case 0:
    close(sv[0]);
    child(sv[1]);
    break;
  case -1:
    perror("fork");
    exit(1);
  default:
    close(sv[1]);
    parent(sv[0]);
    break;
  }
  return 0;
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-10-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 历史
  • 管道
相关产品与服务
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档