使用信号量限制连接

时间:2010-04-16 13:06:33

标签: java sockets

我试图限制我的服务器使用信号量接受的连接数,但是在运行时,我的代码似乎没有这个限制 - 我是否正确使用信号量?例如。我已将许可证号码硬编码为2,但我可以连接无限数量的客户......

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
}

5 个答案:

答案 0 :(得分:0)

您的process方法是什么样的?它可以在你想要它之前返回,因此在你想要它之前释放信号量吗?

答案 1 :(得分:0)

您创建了多少个主题? 1个线程中只有1个服务器实例?或者是2个线程中使用了1个实例?

1个实例/ 1个帖子 - 你的循环正在连续处理, processing 一次接受1个线程。这不是因为信号量,而是因为它只是一个线程。其他连接正在排队等待接受。

1个实例/ 2个线程 - 您的代码(信号量)将您的服务器限制为处理 同时接受 2个连接 ,但TCP / IP允许排队连接(我认为通常的默认队列长度为5)。第三个同步请求(在前两个请求中的任何一个完成处理之前进入的请求)将等待一段时间(我不记得客户端默认等待多长时间)。第4,第5等也是如此。

无论哪种方式:所以你的代码会有无限的连接,因为代码只是限制了接受的数量。一旦接受,连接将保持不变,直到服务器或客户端关闭连接。

更新 - 响应OP评论提供更多信息。

  

进程与无限循环保持持久连接 - 罗伯特12分钟前

答案 2 :(得分:0)

你需要删除finally块

答案 3 :(得分:-1)

你不应该在你的finally块中调用release。最后总是执行块。您要做的是在异常中释放锁定,或者在客户端断开连接时:

    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
        }
    }

然后在客户端代码的适当位置释放锁:

...
//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
...

当然,根据代码的组织方式,有多种方法可以释放锁定,但关键是当你在finally块中调用release时,它将始终执行(使许可可用于下一个传入连接)。因此,只有当存在异常(您知道尚未建立连接)或b)客户端(可能通过服务器上的某种回调/侦听器)时才释放a)在服务器中,当您知道连接是完成/断开/以其他方式终止。

答案 4 :(得分:-1)

信号量不会限制与服务器的连接数。

信号量限制访问特定代码段的线程数。问题,您的服务器将接受所做的传入套接字请求,每个套接字线程将阻塞信号量。

此外,您的run方法包含一个获取和释放信号量的循环,这会导致所有套接字在信号量上循环。

要查看此操作,请添加一些日志语句。一个在获取信号量之前,一个在获取信号量之后立即获得信号量,另一个信号在发布之前,另一个在发布之后立即获得信号量。

那么如何限制与服务器的连接?

检查backlog

上的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); 
}