我如何使用套接字让多个进程与中央进程通信?

时间:2010-03-03 05:57:06

标签: linux unix sockets ipc

对于我的应用程序,我需要一个负责与许多客户端进程交互的中央进程。客户端进程需要一种方法来识别中央进程并与之通信。此外,中央进程可能没有运行,客户端进程需要一种方法来识别该事实。这个应用程序将在类Unix系统上运行,所以我考虑使用命名管道套接字来完成任务。具体来说,我将如何使用命名管道套接字执行此任务(实际代码将不胜感激!)?如果命名管道套接字不理想,是否有更好的替代方案?

5 个答案:

答案 0 :(得分:6)

命名管道并不是非常理想的 - 它们最适合单读者,单作家情况。

然而,UNIX域套接字非常适合它。它们使用套接字API,端点名称是文件系统条目(与命名管道一样)。


这是一个非常简单的示例(您当然希望添加大量的错误检查!)。首先是服务器端:

#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

#define SOCKNAME "/tmp/foo"

int main()
{
    int s1, s2;
    int i;
    struct sockaddr_un sa = { AF_UNIX, SOCKNAME };

    unlink(SOCKNAME);
    s1 = socket(AF_UNIX, SOCK_STREAM, 0);
    bind(s1, (struct sockaddr *)&sa, sizeof sa);
    listen(s1, 5);

    for (i = 0; i < 10; i++)
    {
        struct sockaddr_un sa_client;
        socklen_t sa_len = sizeof sa_client;
        FILE *f;

        s2 = accept(s1, (struct sockaddr *)&sa_client, &sa_len);
        f = fdopen(s2, "r+");
        fprintf(f, "Hello, you are client number %d\n", i + 1);
        fclose(f);
    }

    return 0;
}

现在是客户端:

#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>

#define SOCKNAME "/tmp/foo"

int main()
{
    int s1;
    struct sockaddr_un sa = { AF_UNIX, SOCKNAME };
    FILE *f;
    char buffer[1024];

    s1 = socket(AF_UNIX, SOCK_STREAM, 0);
    connect(s1, (struct sockaddr *)&sa, sizeof sa);
    f = fdopen(s1, "r+");

    while (fgets(buffer, sizeof buffer, f) != NULL)
    {
        printf("Message received: %s", buffer);
    }

    fclose(f);

    return 0;
}

请注意,您应该在/var/run/yourappname而不是/tmp下创建套接字。

man 7 unix是进一步调查的好资源。

答案 1 :(得分:0)

这是一个已经使用数据库的应用程序吗?如果是这样,我会使用它而不是添加另一个完整的通信媒体。

答案 2 :(得分:0)

D-Bus提供面向对象的IPC,另外还包括一个激活功能,如果服务器进程尚未运行,它将启动服务器进程。缺点是网络封装基本上是DIY。

答案 3 :(得分:0)

您需要阅读有关该主题的标准教科书之一 - 可能是Stevens'UNIX Network Programming, Vol 1, 3rd Edn'。

你必须做出一些决定,包括:

  • 中央服务器本身是处理所有消息,还是接受来自其他进程的连接,fork并在恢复侦听新连接时将工作委托给其子进程?
  • 中央服务器是否需要保持会话运行,或者只是一次响应“一条(短)消息”?

这些决定从根本上影响了所需的代码。如果进程一次处理一条短消息,则考虑UDP而不是TCP可能是合适的。如果该过程正在处理与几个通讯员的扩展对话并且不会让孩子处理它们,那么您可以考虑线程编程是否合适。如果没有,您需要考虑及时性以及中央流程是否可以无限期地保留。

如评论所示,您还需要考虑流程应如何处理未运行的中央流程 - 您需要考虑响应应该有多快。您还必须防止中央进程如此忙碌以至于它看起来没有运行,即使它正在运行但只是非常忙于处理其他连接。如果无法连接到中央进程的进程尝试启动它的新副本,您会遇到多少麻烦。

答案 4 :(得分:0)

根据你问题中的信息,听起来你正在构建一个分布式系统,它有一个中央消息传递总线,组件用于通信。我建议使用TCP套接字,原因如下:

  1. TCP套接字可让您灵活地在同一台计算机或不同的计算机上运行这些进程。
  2. AFAIK,在两个进程都在同一台机器上的情况下,许多TCP实现(例如Linux上的实现)将识别这一点并使TCP堆栈短路,使TCP套接字与本地Unix域套接字一样快。 / LI>
  3. 使用TCP,您可以实施“TCP Ping”,允许您的客户端检测中央进程是否正在运行/响应并识别该进程。您可以在CPAN上的Perl Net::Ping包中看到“TCP Ping”的实现。网络源足够接近C,您应该能够理解它。它基本上是一个非阻塞的TCP连接。
  4. 您可以设置inetd以在尝试连接时自动启动服务。由于您可能只希望一次运行一个副本,因此您将使用wait参数。这有副作用,如果服务崩溃,下一次连接尝试将导致inetd重新启动它。 See this example