Unix домен: connect(): нет такого файла или каталога

Как указано в заголовке, мой вызов connect() для сокета типа домена unix с соответствующим адресом приводит к ошибке ENOENT: такого файла или каталога нет.

Два сокета правильно инициализированы, а файлы сокетов созданы и связаны соответствующим образом. Сокеты сервера и клиента выполняются в другом процессе, хотя клиентский процесс имеет функции fork() и execl()-ed. Это также, как я анализирую адрес для сокета клиента и сервера, который я использую для настройки сокета клиента. Серверный процесс использует pthreads.

Вот моя попытка подключения ():

    struct sockaddr_un address;
    address.sun_family = AF_UNIX;
    memcpy(address.sun_path, filepath.c_str(), filepath.length());
    address.sun_path[filepath.length()] = '\0';

    if(-1 == connect(this->unix_domain_descriptor_.descriptor(),       \
                     (struct sockaddr*)&address,                       \
                     size))
    {
        global::ExitDebug(-1, "connect() failed", __FILE__, __LINE__);
        return -1;
    }

Я пробовал разные значения для размера, такие как:

//  this is from unix(7) man page. It doesn't work neither with nor without "+1"
socklen_t size =  offsetof(struct sockaddr_un, sun_path);
          size += strlen(address.sun_path) + 1;

//  this is from one of my books about linux programming
socklen_t size = sizeof(address);

//  this is from a sample code which I found at the internet
socklen_t size = sizeof(address.sun_family) + strlen(address.sun_path);

//  Update 1: 
socklen_t size = SUN_LEN(&address);

//  this is what I tried out after looking into the declaration
//  of struct sockaddr_un
socklen_t size = strlen(address.sun_path);

Удивительно, но все инициализации, кроме последней, приводят к ошибке EINVAL: неверный аргумент для connect(), и я получаю сообщение ENOENT: такого файла или каталога нет только с последним. Я даже опробовал целые примеры из интернета, но безуспешно. И очевидно, что замена socklen_t на size_t или int ничего не меняет.

Я уже проверил это:

  • address.sun_path содержит правильный путь к файлу сокета, начиная с корневого каталога
  • address.sun_path имеет длину 61 символа
  • address.sun_family установлен в AF_UNIX / AF_LOCAL
  • address.sun_family имеет размер 2 байта
  • нет ошибок при создании и привязке обоих сокетов
  • сокет сервера находится в состоянии прослушивания
  • sizeof(адрес) возвращает 110, как это должно быть

Теперь мне было интересно, почему пример справочной страницы не работает и были ли изменения, которые не были обновлены на http://linux.die.net/ или http://www.kernel.org/. Моя ОС - Debian Squeeze, если это актуально.

Есть идеи, что я делаю не так? И как это решить? Если вам нужно больше кода или у вас есть вопросы, не стесняйтесь спрашивать меня (хотя мне, возможно, и не нужно указывать это, но это мой первый пост здесь>. <).

кстати, извините за мой плохой английский

Обновление 2

Решаемые. Я опубликую это в дополнительном ответе ниже для ясности.

2 ответа

Узнав, что я правильно обрабатывал сокеты, я немного изменил свой код для connect(), и теперь он работает. Я просто добавил эту строку после объявления моей переменной:

memset(&address, 0, sizeof(struct sockaddr_un));

Кто-нибудь знает, почему мне нужно установить всю переменную в 0, чтобы она работала? Должен ли я спросить об этом в новой теме или я могу спросить это здесь?

Цитирование из руководства glibc:

Вы должны вычислить параметр LENGTH для адреса сокета в локальном пространстве имен как сумму размера sun_family компонент и длина строки (не размер выделения!) строки имени файла. Это можно сделать с помощью макроса SUN_LEN:

  • Макрос: int SUN_LEN (_struct sockaddr_un *_ PTR)
    Макрос вычисляет длину адреса сокета в локальном пространстве имен.

В следующем примере используется вычисление, для которого, как вы говорите, оно не выполняется:

size = (offsetof (struct sockaddr_un, sun_path)
       + strlen (name.sun_path) + 1);

Но вы должны попробовать этот макрос. Если что-то изменилось или пример неверный, все еще есть хороший шанс, что этот макрос работает как задумано. Если это так, вы можете посмотреть на его внутренности. На первый взгляд мне кажется, что макросу не хватает + 1 часть используется во всех примерах. Что соответствует предупреждению из руководства, чтобы использовать "не размер распределения!" Как ваш пост говорит, что это не работает без + 1 либо шансы невелики.

Из любопытства, какова длина пути? Вы проверили, является ли поле, представленное в структуре, достаточно большим, чтобы вместить его? Что такое sizeof(address.sun_path) в вашей реализации? Интересно, возможно, вы копируете в незарезервированную память, и часть пути перезаписывается при следующем вызове функции.

Другие вопросы по тегам