Как бы я использовал сокет для связи нескольких процессов с центральным процессом? - PullRequest
2 голосов
/ 03 марта 2010

Для моего приложения мне нужен центральный процесс, отвечающий за взаимодействие со многими клиентскими процессами. Клиентские процессы нуждаются в способе идентификации и связи с центральным процессом. Кроме того, центральный процесс может не работать, и клиентскому процессу необходим способ определить этот факт. Это приложение будет работать в Unix-подобной системе, поэтому я подумал об использовании именованных каналов сокетов для этой задачи. Как мне, в частности, пойти на использование именованных каналов сокетов для этой задачи (реальный код был бы очень полезен!) Если именованные каналы розетки не идеальны, есть ли лучшие альтернативы?

Ответы [ 5 ]

6 голосов
/ 03 марта 2010

Именованные каналы на самом деле не идеальны для этого - они лучше всего подходят для ситуаций с одним читателем и с одним автором.

Сокеты 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 - хороший ресурс для дальнейшего изучения.

0 голосов
/ 03 марта 2010

Судя по информации в вашем вопросе, создается впечатление, что вы строите распределенную систему с центральной шиной для передачи сообщений, которую компоненты используют для связи. Я бы порекомендовал сокеты TCP по следующим причинам:

  1. Сокеты TCP предоставят вам гибкость для запуска процессов на одном и том же компьютере или на отдельных компьютерах.
  2. AFAIK, в случае, когда оба процесса находятся на одном компьютере, многие реализации TCP, такие как Linux, распознают это и закорачивают стек TCP, делая сокет TCP таким же быстрым, как локальный сокет домена Unix. 1006 *
  3. Используя TCP, вы можете реализовать «Пинг TCP», позволяющий вашим клиентам определять, работает ли центральный процесс или реагирует на них, и идентифицировать этот процесс. Вы можете увидеть реализацию TCP Ping в пакете Perl Net :: Ping на CPAN. Сетевой источник достаточно близок к C, чтобы вы могли его понять. Это в основном неблокирующее TCP-соединение.
  4. Вы можете настроить inetd для автоматического запуска службы при каждой попытке подключения. Поскольку вы, вероятно, хотите, чтобы за один раз выполнялась только одна копия, вы должны использовать параметр ожидания. Это приводит к побочному эффекту: в случае сбоя службы при следующей попытке подключения inetd перезапустит ее. См. Этот пример .
0 голосов
/ 03 марта 2010

Вам нужно прочитать один из стандартных учебников по этому предмету - вероятно, Сетевое программирование UNIX Стивенса, том 1, 3-е издание '.

Вы должны принять ряд решений, в том числе:

  • Обрабатывает ли центральный сервер все сообщения сам или принимает соединение от другого процесса, разветвляется и делегирует работу своему дочернему элементу, пока он возобновляет прослушивание новых соединений?
  • Нужно ли центральному серверу поддерживать сеанс в работе или он просто отвечает на «одно (короткое) сообщение за раз»?

Эти решения радикально влияют на код, который требуется. Если процесс имеет дело с одним коротким сообщением за раз, может быть целесообразно рассмотреть UDP вместо TCP. Если этот процесс имеет дело с расширенными беседами с несколькими корреспондентами и не разветвляет ребенка, чтобы справиться с ними, тогда вы можете подумать, уместно ли многопоточное программирование. Если нет, вам нужно подумать о своевременности и о том, можно ли продлить центральный процесс на неопределенный срок.

Как указано в комментарии, вам также необходимо учитывать, как процесс должен работать с центральным процессом, который не запущен, и вам необходимо учитывать, насколько быстрым должен быть этот ответ. Вы также должны защищаться от того, чтобы центральный процесс был настолько занят, что кажется, что он не запущен, даже если он запущен, но просто очень занят работой с другими соединениями. С какими трудностями вы столкнетесь, если процесс, который не может подключиться к центральному процессу, попытается запустить его новую копию.

0 голосов
/ 03 марта 2010

D-Bus обеспечивает объектно-ориентированный IPC, плюс включает функцию активации, которая запускает процесс сервера, если он еще не запущен.Недостатком является то, что сетевая инкапсуляция в основном сделана своими руками.

0 голосов
/ 03 марта 2010

Это приложение, которое уже использует базу данных? Если это так, я бы использовал это, а не добавлял еще одну целую коммуникационную среду к миксу.

...