Дублирование сокетов при разветвлении процесса на C

Я изучаю сетевое программирование и пытаюсь реализовать HTTP-сервер. Я следую руководству по программированию сокетов на C (https://beej.us/guide/bgnet/html/split/client-server-background.html) и наткнулся на этот пример:

while(1) {  // main accept() loop
    sin_size = sizeof their_addr;
    new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
    if (new_fd == -1) {
        perror("accept");
        continue;
    }

    inet_ntop(their_addr.ss_family,
        get_in_addr((struct sockaddr *)&their_addr),
        s, sizeof s);
    printf("server: got connection from %s\n", s);

    if (!fork()) { // this is the child process
        close(sockfd); // child doesn't need the listener
        if (send(new_fd, "Hello, world!", 13, 0) == -1)
            perror("send");
        close(new_fd);
        exit(0);
    }
    close(new_fd);  // parent doesn't need this
}

Меня смущает разветвление процессов.

Почему мы закрываем исходный дескриптор файла сокета (sockfd), если он был создан только в исходном родительском процессе? Или, в более общем смысле, все ли ресурсы, созданные родительским процессом, дублируются в дочернем - например, файл сокета?

Если дескрипторы сокетов не были дублированы в дочерний процесс, то создание дочернего процесса для обработки нового соединения вообще не могло бы работать. Верно?

Useless 27.08.2024 12:48

Потому что sockfd — это серверный сокет, который используется только для приема соединений. Дочернему процессу это не нужно для связи с клиентом.

dimich 27.08.2024 12:48

Дескрипторы файлов дублируются таким же образом, как dup() дублирует дескриптор файла, за исключением того, что fork() не меняет значения дескрипторов файлов. Дескриптор файла идентифицируется комбинацией его номера и процесса, которому он принадлежит. Дескрипторы файлов относятся к базовому файлу, который был первоначально открыт, или к сокету или каналу, который был первоначально создан. Базовое открытое описание файла, сокет или канал не освобождается и не уничтожается до тех пор, пока все ссылающиеся на него файловые дескрипторы не будут закрыты.

Ian Abbott 27.08.2024 12:52

Итак, несколько файловых дескрипторов могут быть созданы параллельно «не влияя друг на друга» — по крайней мере, в этом случае, когда принимается одно ожидающее соединение. Спасибо всем за комментарии.

Vanja Stojanović 27.08.2024 17:47

@VanjaStojanović Думайте о файловом дескрипторе как об индексе в таблице ссылок на объекты ядра для каждого процесса. Разные процессы могут ссылаться на разные объекты по одному и тому же индексу в своих таблицах. Разные записи в одной таблице могут ссылаться на один и тот же объект ядра (например, после dup()). После fork() таблица «копируется» так же, как и остальная память процесса.

dimich 28.08.2024 18:21

Логично, я об этом не подумал, спасибо за идею :)

Vanja Stojanović 28.08.2024 18:27
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
6
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Потому что согласно спецификации POSIX fork().

Дочерний процесс должен иметь собственную копию файловых дескрипторов родительского [...].

Суть fork() заключается в том, что ресурсы процессов дублируются, хотя это не на 100% верно, поскольку потоки не дублируются.

Понятно, так что это не просто дублированный указатель, указывающий на один и тот же ресурс, а совершенно новый ресурс. Спасибо.

Vanja Stojanović 27.08.2024 17:46

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