tags:

views:

685

answers:

4

General Programming: In a server socket accept() method what exactly happens. At low level how server sockets are different from client sockets?

+4  A: 

Firstly, server sockets are generally bound to well known names (ports, in this case) and they establish themselves with listen(). That is where the real difference happens, as client sockets establish themselves with connect(). Calling listen() on a socket causes the kernel's tcp/ip implementation to begin accepting connections sent to the socket's bound name (port). This will happen whether or not you ever call accept().

accept() simply gives your server a way to access and interact with the client sockets that have connected to your listening socket.

Jason Coco
Also, if you're using Windows, the MSDN page about Accept() also gives additional information of what happens in practice: http://msdn.microsoft.com/en-us/library/ms737526(VS.85).aspx
porkchop
A: 

It's difficult to fully answer your question without specifying a programming language. I'll answer with respect to python, because for all I know the answer might be representative.

If s is a socket object, then a server first binds to a port by calling s.bind(('',12345)). This creates a socket in server mode. It is prepared to catch data on port 12345.

Then one calls s.listen(10). This throws the socket into server mode. This means that a request for a connection will be received by this socket (up to 10 pending requests at a time).

By the time we get to s.accept(), the operating system already knows we're listening on port 12345. s.accept() merely says what we're going to do with the requests we receive. In python, s.accept() will return (connection,address) where connection is a connection through another port. In this case, connection is not very different from the socket object that the client has opened. It's reasonably symmetric from here on out.

David Berger
+1  A: 

If you are really interested, then I would advise you to read TCP/IP Illustrated, Volume 2. If you want a less "in the guts" answer, then:

  • Server sockets are bound to well-known endpoints where an endpoint is the (protocol, address, port) tuple. The endpoint is formed by the protocol specified in the socket() system call and the addressing information specified in the bind() system call.
  • When the server calls the listen() system call, the network stack creates a queue in which pending connections are placed into. A hint to the size of the queue is given as the backlog parameter to listen().
  • The server then calls accept() to pull a new connection from the queue.
  • Client sockets send messages to server sockets by specifying the server endpoint in a call to connect() and then sending data using send() or write().
  • When the client calls connect(), a connection is pushed onto the server-side queue where it sits until the server accepts the connection.

This description is only really valid for TCP/IP sockets however. The UDP case is simpler and quite different since UDP sockets are not (necessarily) connected.

D.Shawley
+1  A: 

At a low level sockets are just sockets regardless of whether they are being used in a server or client application. The difference between the two lies in the system calls each kind of application makes.

Server sockets will call bind() to be associated with a port. They want to be associated with a port so that other programs know where to reach them. Client sockets can call bind() but almost never do because there is not much point. If a socket doesn't call bind() the OS will just choose an ephemeral port for it, which is fine for clients because they are doing the calling; no one needs to call them.

Server sockets call listen(). This was explained pretty well in the other answers.

Server sockets call accept() and I think this is the crux of your question because it is a bit mysterious at first. The important thing to grasp is that in calling accept() the kernel will pass back a new socket. It is now separate from the original listening socket and is what your server will use to communicate with its peer(s).

The key in understanding how the listening socket continues to listen while the accepted connection is doing its thing is in understanding that tcp connections depend on a 4-tuple of (1) local address (2) local port (3) foreign address (4) foreign port. These define a unique connection. Before accept() passed back the new socket the kernel used these values to create various structures so that in collaboration with the tcp/ip stack all traffic with this tuple will go to the connected socket. Even though your server may have a thousand connections with local address 192.168.1.100 port 80, the client combination of address and port will always be different and thus the tuple is always unique.

Duck