Limit Connections with semaphores
I'm trying to limit the number of connections my server will accept us开发者_开发知识库ing semaphores, but when running, my code doesn't seem to make this restriction - am I using the semaphore correctly? eg. I have hardcoded the number of permit as 2, but I can connect an unlimited number of clients...
public class EServer implements Runnable {
private ServerSocket serverSocket;
private int numberofConnections = 0;
private Semaphore sem = new Semaphore(2);
private volatile boolean keepProcessing = true;
public EServer(int port)
throws IOException {
serverSocket = new ServerSocket(port);
}
@Override
public void run() {
while (keepProcessing) {
try {
sem.acquire();
Socket socket = serverSocket.accept();
process(socket, getNextConnectionNumber());
} catch (Exception e) {
} finally {
sem.release();
}
}
closeIgnoringException(serverSocket);
}
private synchronized int getNextConnectionNumber() {
return ++numberofConnections;
}
// processing related methods
}
What does your process
method look like? Could it be returning before you want it to, hence releasing the semaphore before you want it to?
How many threads are you creating? Just 1 server instance in 1 thread? Or is 1 instance used in 2 threads?
1 instance/1 thread - your loop is processing serially, processing accepting 1 thread at a time. This isn't because of the semaphore, but rather because its just one thread. The other connections are being queued waiting for acceptance.
1 instance/2 threads - your code (the semaphore) is limiting your server up to processing accepting 2 connections simultaneously, but TCP/IP allows for connections to be queued to be accepted (I think the general default queue length is 5). The 3rd simultaneous request (a request that comes in before either of the 2 previous requests finish processing) would wait for a certain amount of time ( I don't recall how long clients wait by default). So would the 4th, 5th, etc.
Either way: So your code would have unlimited connections, because the code is just limiting how many are accepted simultaneously. Once accepted, the connections remain until the server or the client closes the connection.
Updated - in response to OP comments giving more information.
process maintains a persistent connection with an infinite loop – Robert 12 mins ago
you need to remove the finally block
You should not be calling release in your finally block. Finally blocks are always executed. What you want to do is release the lock in the exception, or when your client disconnects:
while (keepProcessing) {
try {
sem.acquire();
Socket socket = serverSocket.accept();
process(socket, getNextConnectionNumber());
} catch (Exception e) {
//Here the client hasn't been connected, so release the lock.
sem.release();
} finally {
//code here always executes, exception or not
}
}
Then in an appropriate place in your client code release the lock:
...
//The client is shutting down / disconnecting
serverInstance.sem.release(); //not good OOP
OR
serverInstance.clientFinished(); //callback, where clientFinished in your server class will release the lock
...
Of course there are various ways to release the lock depending on how your code is orgnized, but the key is that when you call release in the finally block it will always execute (making the permit available for the next incoming connection). So only release it a) in the server when there is an exception (you know a connection hasn't been made) or b) in the client (possibly via some kind of callback/listener on the server) when you know the connection is finished / disconnected / otherwise terminated.
A semaphore will not limit number of connections to server.
A semaphore limits the number of threads accessing a particular section of code. Ergo, your server will accept as many incoming socket requests as are made, but each socket thread will block on the semaphore.
Furthermore, your run
method contains a loop which is acquiring and releasing the semaphore, which results in all sockets round-robin-ing on the semaphore.
To see this in action, add a few log statements. One before acquiring the semaphore, one more immediately after acquiring it, another before releasing, and a final one immediately after releasing it.
So how does one limit connections to a server?
Check the backlog
constructor parameter on ServerSocket
public EServer (int port)
throws IOException
{
// 'backlog' is in fact a listening queue length.
// if more than 2 socket requests are made at a time,
// they are refused. probably want to parameterize
// this :)
serverSocket = new ServerSocket (port, 2);
}
精彩评论