【问题标题】:Socketpair() in C/UnixC/Unix 中的 Socketpair()
【发布时间】:2012-07-12 18:00:48
【问题描述】:

我在同一个系统上有 2 个应用程序需要来回通信。根据我的研究,我认为这称为进程间通信,使用 socketpair() 是解决我的问题的最佳方法。

我(字面意思)试图开始在 C 中使用 socketpair() 创建套接字。据我了解,套接字是一个非常复杂的话题,而我作为一个新手 C 程序员肯定无济于事.

我在过去的 48 小时内搜索了谷歌,阅读了教程等,但我仍然无法得到它。我理解这个概念,但代码太混乱了。这篇文章我看了几遍:http://beej.us/guide/bgnet/html/single/bgnet.html,但还不够简单。

谁能提供一些例子(这么简单的五年级学生可以理解)或指出一个好的教程?

【问题讨论】:

  • 请不要把头发扯下来。这听起来很痛苦。我们需要回答的第一个问题是:这两个程序是否有共同的祖先?也就是说,一个会启动另一个吗?还是它们是由您编写的第三个程序启动的?还是它们是相互独立启动的?
  • 老兄,IPC 与套接字无关。这是完全不同的事情。而不是按照您发布的链接,您应该按照这个.....beej.us/guide/bgipc/output/html/multipage/…
  • 这两个程序由一个共同的祖先连接起来。
  • 这个例子很棒!正是我想要的!
  • @Aftnix 我只是猜测您前几天正在寻找那种“善良”的食品补充剂。您链接到的那篇文章在第三段下面有这个美味的部分:“您可以立即使用这些套接字描述符进行进程间通信。”。在我的首字母缩略词中,这就是 IPC。嘿,看看“dude”的用户名!除非她/他是在开玩笑,否则她/他实际上可能成为火箭科学家,值得更多尊重(恕我直言,FWIW)。

标签: c sockets unix ipc


【解决方案1】:

您只能在创建两个进程的地方使用socketpair,如下所示:

  1. 调用socketpair - 现在你有两个套接字文件描述符(单个管道的两端)
    • 指定一端为端,另一端为端。没关系,做个选择,以后再坚持
  2. 调用fork - 现在你有两个进程
    1. 如果fork 返回零,您就是孩子。关闭 parent 文件描述符,保留 child 描述符,并将其用作此进程的管道末端
    2. 如果fork 返回非零,您就是父级。关闭 child 文件描述符,保留 parent 一个并将其用作管道的末端
  3. 您现在有两个进程,每个进程都有一个文件描述符,代表同一管道的不同端。请注意,两个进程都在运行同一个程序,但在调用fork 后它们遵循不同的分支。如果 parent 在其套接字上调用 writechild 将能够从 套接字读取该数据,反之亦然

下面是直接翻译成代码:

void child(int socket) {
    const char hello[] = "hello parent, I am child";
    write(socket, hello, sizeof(hello)); /* NB. this includes nul */
    /* go forth and do childish things with this end of the pipe */
}

void parent(int socket) {
    /* do parental things with this end, like reading the child's message */
    char buf[1024];
    int n = read(socket, buf, sizeof(buf));
    printf("parent received '%.*s'\n", n, buf);
}

void socketfork() {
    int fd[2];
    static const int parentsocket = 0;
    static const int childsocket = 1;
    pid_t pid;

    /* 1. call socketpair ... */
    socketpair(PF_LOCAL, SOCK_STREAM, 0, fd);

    /* 2. call fork ... */
    pid = fork();
    if (pid == 0) { /* 2.1 if fork returned zero, you are the child */
        close(fd[parentsocket]); /* Close the parent file descriptor */
        child(fd[childsocket]);
    } else { /* 2.2 ... you are the parent */
        close(fd[childsocket]); /* Close the child file descriptor */
        parent(fd[parentsocket]);
    }
    exit(0); /* do everything in the parent and child functions */
}

请注意,这只是示例代码:我省略了所有错误检查和合理的流协议。


如果您希望两个独立 程序进行通信(例如,您有一个名为client 的可执行文件和一个名为server 的可执行文件),您可以不要使用这种机制。相反,您可以:

  • 使用 UNIX 套接字(其中一台主机上的 IPC 管道由文件名标识 - 仅当 clientserver 在同一台机器上运行时才有效)
  • 或使用 TCP/IP 套接字(其中 IP 地址和端口标识管道,客户端服务器可以在不同的机器上)

如果您特别不需要套接字,并且您很乐意要求 clientserver 在同一台机器上运行,您还可以使用共享内存或消息队列。

【讨论】:

  • 它们可以是具有共同祖先的独立程序。只需使用execl(或其他 exec 调用)运行程序,它将继承套接字。您只需要一种方法来告诉程序使用它继承的套接字。
  • 是的,但是当您拥有该协议时,显然并不比仅使用 UNIX 套接字容易得多
  • 其实可以将描述符传递给不相关的进程:见sendmsg/recvmsg和“描述符传递”。这似乎是一个流行的搜索:)
  • 当然:它们仍然只是管道的两端,一个或另一个子进程没有什么特别之处。
  • 为什么在父子进程中关闭socket的另一端?那有必要吗?并且可以使用socketpair在同一个进程的两个线程之间进行通信吗?
【解决方案2】:

socketpair 创建一个 匿名 套接字对,通常是 unix/local 套接字,它们仅用于父进程和子进程之间的通信或其他需要使用它们的进程的情况可以从一个共同的祖先那里继承文件描述符。

如果你要在不相关的(在父子关系的意义上)进程之间进行通信,你需要使用socketbindconnect在一个进程中创建一个监听套接字并创建一个客户端socket 在另一个进程中连接到它。

【讨论】:

  • 奇怪的是,我发现 socketpair 示例代码 只需搜索该短语即可。我提供了一些,但我很惊讶这是必要的
  • @Useless:这个搜索听起来毫无用处,因为我指出socketpair 可能不是 OP 想要做的正确工具。
【解决方案3】:

对于两个进程之间的通信,是的,进程间通信或 IPC 是您应该寻找的。 套接字只是通信的一种方法,如果您必须实现一对多连接,它会很有用。意味着,一个服务器进程以请求-响应方式与许多客户端进程通信。由于您是 IPC 的新手,因此套接字地址和所涉及的细节可能看起来难以掌握是可以理解的。 (虽然你会在适当的时候发现它们很容易:-))

对于您的问题,我建议您使用更简单的 IPC 机制,例如 Pipe、FIFO、Message Queue。 我不确定您是如何得出使用 socketpair 的结论的。由于您没有提及您需要的设计或 IPC 类型的任何内容,并且基于使用水平,我强烈建议您查看某些书籍或互联网中的 Pipe 或 FIFO 示例代码。它们应该看起来比套接字更容易实现并且工作得更快。

【讨论】:

  • FIFO 是什么意思(帖子表明它与 Pipe 不同)?
【解决方案4】:

使用 TCP/IP。虽然还有其他可用的 IPC 机制(例如 Unix 域套接字和 SYSV IPC),但出于多种原因,您最好使用 TCP/IP。以下是一些:

  1. 网上有很多教程和其他信息描述了如何进行 TCP/IP
  2. 与 Unix 域套接字甚至 SYSV IPC 相比,现代系统,尤其是 Linux 和 *BSD,对使用 TCP/IP 没有明显的影响。
  3. 您可以将许多库和框架用于通过 TCP/IP 进行通信的应用程序。

我不会使用 TCP/IP 在两个“程序”之间进行通信的唯一情况是它们实际上是线程而不是单独的程序。

【讨论】:

  • 我一定不同意。在本地进程之间使用 TCP/IP 进行 IPC 有很多缺点,最大的一个缺点是您必须关注与来自远程主机甚至本地主机上的进程的可能连接相关的安全问题。 Unix(本地)套接字更容易保护,如果您将以主机的二进制格式传输数据,则更合适。你还可以做一些有用的事情,比如在它们上面传递文件描述符。
  • Unix 套接字肯定更快。只需考虑 tcp 必须经历创建 IP 打包并通过环回设备发送它、应用过滤规则等的所有循环。
猜你喜欢
  • 1970-01-01
  • 2014-02-28
  • 1970-01-01
  • 1970-01-01
  • 2016-09-14
  • 1970-01-01
  • 2017-11-03
  • 2015-04-02
  • 2014-04-26
相关资源
最近更新 更多