Как исправить `` Адрес уже используется '', возвращаемый bind () в AF_UNIX

Я знаком с сокетами Unix для межпроцессного взаимодействия и следую руководству здесь. Каждый раз, когда я запускаю программу, которая действует как сервер (в руководстве она называется echos.c), я получаю сообщение об ошибке bind: Address already in use, за исключением первого запуска после удаления всех файлов сборки.

Ошибка исходит из этого раздела кода:

#define SOCK_PATH "echo_socket"

int main(void)
{
    int s, s2, len;
    socklen_t t;
    struct sockaddr_un local, remote;
    char str[100];

    if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(1);
    }

    local.sun_family = AF_UNIX;
    strcpy(local.sun_path, SOCK_PATH);
    unlink(local.sun_path);
    len = strlen(local.sun_path) + sizeof(local.sun_family);
    if (bind(s, (struct sockaddr *)&local, len) == -1) {
        perror("bind");
        exit(1);
    }

    // ...

При первоначальном запуске программа создает файл сокета с именем echo_socke (я проверил это с помощью ls -l, и странно, что в имени отсутствует буква 't', чтобы получилось echo_socket), а затем успешно переходит к bind и listen для клиентский процесс.

Однако при последующих запусках, когда я не удаляю файлы сборки, я получаю ошибку bind: Address already in use, исходящую из строк

if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
     perror("socket");
     exit(1);
}

Выполняя дополнительное тестирование, я обнаружил, что unlink(local.sun_path) возвращает ошибку No such file or directory, поэтому я полагаю, что файл сокета, к которому bind пытается получить доступ, не найден. Может ли это быть из-за того, что в имени файла отсутствует символ, как упоминалось ранее? (Но это срабатывает с первого раза, так что не может быть?). Любая помощь в выяснении того, что происходит, будет очень признательна.


person Brendonovich    schedule 28.10.2019    source источник
comment
Вы неправильно рассчитываете len. См. man 7 unix. Это должно быть offsetof(struct sockaddr_un, sun_path)+strlen(local.sun_path)+1.   -  person user207421    schedule 28.10.2019
comment
@ Нина Это AF_UNIX. Нет портов.   -  person user207421    schedule 28.10.2019
comment
@ user207421 Это помогло, большое спасибо!   -  person Brendonovich    schedule 28.10.2019
comment
Объяснение заключается в том, что bind() ожидает, что длина будет содержать конечный ноль, как вы можете видеть из формулы. Таким образом, он предположил, что последний символ был завершающим нулем, и усек имя. Итак, ваш unlink() не отключил его, значит, он все еще был там, так что «адрес уже используется». Конечно, при подключении нужно использовать ту же формулу.   -  person user207421    schedule 28.10.2019
comment
Ааааааааааааа, имеет смысл. Код, который я использовал, был таким же, как в учебнике, поэтому я решил, что все будет хорошо. Клиент теперь тоже работает, спасибо!   -  person Brendonovich    schedule 28.10.2019
comment
Я должен перефразировать это. Предполагается, что последний символ не является частью имени, поэтому он использует только offsetof(struct sockaddr_un, sun_path)+strlen(local.sun_path) байтов структуры. Паршивый дизайн. Они не должны были требовать +1. Слишком поздно.   -  person user207421    schedule 28.10.2019