Что происходит, когда tcp-сервер связывается и разветвляется перед выполнением принятия? Какой процесс будет обрабатывать клиентские запросы? - PullRequest
1 голос
/ 27 января 2012

В Linux я написал стандартный tcp сервер (с использованием интернет-сокетов) с небольшой разницей. Это скелет сервера

fd=socket(...);
bind(...);
listen(...);
//now do a fork
fork(); 
//this will create two processes bound to the same server listening on the same port !!

clientfd=accept(...);

Что произойдет, когда клиент подключится к серверу через порт прослушивания. Какой процесс примет соединение?

Из практических запусков программы всегда родитель (процесс, который разветвлялся) получал запрос клиента. Я хочу знать теорию, стоящую за этим. Случайно ли родительский процесс получал запрос?

Теперь я убил родительский процесс. Таким образом, выполняется только дочерний процесс. Когда клиент пытался подключиться к серверу с тем же номером порта, дочерний (или одинокий выживший) процесс получил соединение. Чем объясняется такое поведение?

Ответы [ 2 ]

3 голосов
/ 09 июля 2013

Я только что проверил это поведение в Linux 3.4, и его поведение таково, что ядро ​​будет выполнять циклическое переключение среди всех дочерних элементов, которые вызывают accept().

Это поведение можно увидеть в следующем примере Pythonscript:

import socket
import os

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('127.0.0.1', 4242))
s.listen(10)
os.fork()
os.fork()
os.fork()
while True:
   conn, addr = s.accept()
   print 'I am %d and I accepted %s' % (os.getpid(), addr)
   conn.close()

Это создаст 8 процессов, все привязаны к порту 4242. Затем вы можете подключиться локально через nc localhost 4242 и посмотреть, какой PID принимает подключение.

edit: ЕслиВы делаете это из более традиционного цикла select, затем все процессы пробуждаются, и происходит вызов по вызову accept(), при котором все процессы, кроме одного, застряли в accept() (что плохоблокирует цикл выбора).

2 голосов
/ 27 января 2012

Реализация Linux wait_queue_head состоит из упорядоченной структуры данных (связанный список, служащий очередью). Новые задачи ожидания добавляются в конец очереди, и пробуждения выполняются из головы (см. __wake_up_common в kernel/sched.c). Кроме того, просыпается только одна задача (как во многих местах, кроме кода сокета), потому что планирование всех задач часто бессмысленно, когда только одна задача может получить рассматриваемый ресурс (см. Комментарии в inet_csk_wait_for_connect в net/ipv4/inet_connection_sock.c).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...