tags:

views:

738

answers:

7

I'm writing a client-server pair in C++ using Linux sockets. I want the server to listen for a connection, and while one client is connected the server should reject any other clients that try to connect.

I tried implementing this by setting the backlog parameter in the listen function to 0 and to 1 and neither one of those values seems to work. The first client connects as expected, but any subsequent clients just block while the first client finishes. What's really confusing to me is that they don't block on connecting to the server, they block on the first read.

I used the code here to get started writing my client and server. Does anyone know what I need to change to get the server to accept only one client connection, and drop any subsequent connection attempts?

+3  A: 

When you accept a connection, a new socket gets created. The old one is still used to listen for future connections.

Since you want to only allow 1 connection at a time, you could just accept the connections, and then close the new accepted socket if you detect you are already processing another.

Is there a net difference that you are looking for compared to closing the new accepted socket right after the accept? The client will know as soon as it tries to use its socket (or right away if it is already waiting on the server with a read call) with a last error of: server actively closed the connection.

Brian R. Bondy
I'm modifying my code to see if I can do this. I'll get back to you...
Bill the Lizard
+1 exactly what I was about to suggest.
Daniel Earwicker
+4  A: 

Just don't fork() after accept().

This pseudo-C-code will only accept one client at once.

while(1) {
    listen()
    accept()
    *do something with the connection*
    close()
}
Johannes Weiß
I don't fork(). The example is a simple echo server that just processes the request.
Bill the Lizard
+3  A: 

You could close your original socket that's listening for connections after accepting the first connection. I don't know if the socket class you're using will allow you to do that though.

Chris AtLee
That's an idea, but I want it to accept new connections after the first one is done processing.
Bill the Lizard
@Bill, then re-open the socket when you're ready to accept connections again.
Paul Tomblin
+3  A: 

Sounds like you need to implement it manually. Let a client connect, then send a disconnect message from the server to the client if there's already another client connected. If the client receives this message let it disconnect itself.

DaClown
A: 

If you have control over the clients, you can make the sockets non-blocking. In this case they'll return the error message EINPROGRESS.

I'm still looking for how to change the socket to be non-blocking. If anybody know how to offhand, feel free to edit the answer.

Nathan Fellman
A: 

let the listening socket die after accepting and starting a new connection. Then when that connection is done, have it spin off a new listening socket.

royatl
A: 

You might have the socket option TCP_DEFER_ACCEPT set on your listening socket:

TCP_DEFER_ACCEPT (since Linux 2.4)
    Allows  a  listener to be awakened only when data arrives on the socket.
    Takes an integer value (seconds), this can bound the maximum  number  of
    attempts  TCP  will make to complete the connection.  This option should
    not be used in code intended to be portable.

I would assume it would lead to the effect you described, that the connecting client doesn't block on the connect, but on the subsequent read. I'm not exactly sure what's the options default setting and to what it should be set to disable this behavior, but probably a value of zero is worth a try:

int opt = 0;
setsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, &opt, sizeof(opt));
sth