1

In linux, I have written a standard tcp server(using internet sockets) with a small difference. This is the skeleton of the server

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(...);

What will happen when a client connects to the server on the listening port. Which process will accept the connection ?

From the practical runs of the program, always the parent(the process which forked) was getting the client request. I want to know the theory behind this. Was it just accidental that the parent process was getting the request ?

Now I killed the parent process. So there is only child process running. When a client tried to connect to the server on the same port number, the child(or the lone survivor) process got the connection. How is this behavior explained ?

Saradhi
  • 477
  • 6
  • 13

2 Answers2

3

I just tested this behavior on Linux 3.4 and the way it behaves is that the kernel will round-robing amongst all children that are calling accept().

You can see this behavior from the following example Python script:

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()

This will create 8 processes, all bound to port 4242. You can then connect locally via nc localhost 4242 and observe what PID is accepting the connection.

edit: If you do this from within a more traditional select loop, then all the processes get awaken and there is a race on the call to accept(), with all but one of the processes getting stuck in accept() (which is bad as it blocks the select loop).

tsuna
  • 1,836
  • 14
  • 21
2

The Linux wait_queue_head implementation consists of an ordered data structure (linked list serving as a queue). New waiting tasks are added to the end of the queue, and wakeups are done from the head (cf. __wake_up_common in kernel/sched.c). Furthermore, only a single task is woken up (like in many places besides socket code), because having to schedule all tasks is often pointless when only a single task can get the resource in question (cf. comments in inet_csk_wait_for_connect in net/ipv4/inet_connection_sock.c).

jørgensen
  • 10,149
  • 2
  • 20
  • 27