views:

69

answers:

2

Hi,

I was wondering how tcp/ip communication is implemented in unix. When you do a send over the socket, does the tcp/level work (assembling packets, crc, etc) get executed in the same execution context as the calling code?

Or, what seems more likely, a message is sent to some other daemon process responsible for tcp communication? This process then takes the message and performs the requested work of copying memory buffers and assembling packets etc.? So, the calling code resumes execution right away and tcp work is done in parallel? Is this correct?

Details would be appreciated. Thanks!

A: 

No - there is no parallel execution. It is true that the execution context when you're making a system call is not the same as your usual execution context. When you make a system call, such as for sending a packet over the network, you must switch into the kernel's context - the kernel's own memory map and stack, instead of the virtual memory you get inside your process.

But there are no daemon processes magically dispatching your call. The rest of the execution of your program has to wait for the system call to finish and return whatever values it will return. This is why you can count on return values being available right away when you return from the system call - values like the number of bytes actually read from the socket or written to a file.

I tried to find a nice explanation for how the context switch to kernel space works. Here's a nice in-depth one that even focuses on architecture-specific implementation:

http://www.ibm.com/developerworks/linux/library/l-system-calls/

Igor
While the call to `send()` will not return immediately, it will return before the data appears on the wire. So it does send in parallel to the execution of the app code.
Aaron Digulla
hmmm, good point, aaron. i guess the answer is: it's complicated. some work definitely happens right away, and some happens later, in parallel with your own code. so my unequivocal 'no' is wrong.
Igor
@Igor currently reading "unix network programming" from Richard W. Stevens, I only agree with Aaron answer. Kernel performs all the TCP stuff for you (for your application), such as resending un-acknowledged paquet after a timeout; Let's go further: meanwhile all new call to send() from your application may actually buffer the data if the full TCP window size is reached. (I may not be exactly correct, I am not a tcp guru myself, but the idea is here ..) -1.
yves Baumes
+1  A: 

The TCP/IP stack is part of your kernel. What happens is that you call a helper method which prepares a "kernel trap". This is a special kind of exception which puts the CPU into a mode with more privileges ("kernel mode"). Inside of the trap, the kernel examines the parameters of the exception. One of them is the number of the function to call.

When the function is called, it copies the data into a kernel buffer and prepares everything for the data to be processed. Then it returns from the trap, the CPU restores registers and its original mode and execution of your code resumes.

Some kernel thread will pick up the copy of the data and use the network driver to send it out, do all the error handling, etc.

So, yes, after copying the necessary data, your code resumes and the actual data transfer happens in parallel.

Note that this is for TCP packets. The TCP protocol does all the error handling and handshaking for you, so you can give it all the data and it will know what to do. If there is a problem with the connection, you'll notice only after a while since the TCP protocol can handle short network outages by itself. That means you'll have "sent" some data already before you'll get an error. That means you will get the error code for the first packet only after the Nth call to send() or when you try to close the connection (the close() will hang until the receiver has acknowledged all packets).

The UDP protocol doesn't buffer. When the call returns, the packet is on it's way. But it's "fire and forget", so you only know that the driver has put it on the wire. If you want to know whether it has arrived somewhere, you must figure out a way to achieve that yourself. The usual approach is have the receiver send an ack UDP packet back (which also might get lost).

Aaron Digulla
thanks, just what i needed to know!
rsinha