【问题标题】:Creating the ServerSocket in a separate thread?在单独的线程中创建 ServerSocket?
【发布时间】:2013-03-21 07:33:18
【问题描述】:

在我的应用程序中使用 ServerSocket 时遇到问题。

我正在我的应用程序的构造函数中创建ServerSocket。 socket的构造函数调用accept()方法等待客户端连接。

问题是accept() 方法正在冻结我的整个应用程序,直到客户端连接。所以我想问一下,除了在单独的线程中创建整个 ServerSocket 之外,是否还有其他方法可以在我的主应用程序旁边调用 ServerSocket 及其 accept() 方法的构造函数?

编辑:

感谢 Olivier 的建议,将 .accept 放入可运行文件并创建线程池来处理客户端连接。

这就是我现在的代码:

  public void start(){

      final ExecutorService clientProcessingPool = Executors.newFixedThreadPool(10);

      Runnable serverTask = new Runnable() {
          @Override
          public void run() {

              try {
                  serverSocket = new ServerSocket(port);

                  while (true) {
                      Socket clientSocket = serverSocket.accept();
                      objectout = new ObjectOutputStream(clientSocket.getOutputStream());
                      clientProcessingPool.submit(new ClientTask(clientSocket,objectout)); 
                  }
              } catch (IOException e) {
                  System.err.println("Accept failed.");
              }

          }
      };

一切正常!谢谢!

【问题讨论】:

  • 尝试在单独的线程中移动套接字相关代码?遇到什么具体问题?
  • 看看java.nio.channels.AsynchronousServerSocketChannel,看看它是否符合你的要求。
  • 或者更好,看看这个问题:stackoverflow.com/questions/8940747/…
  • 我的问题是它不足以将 ServerSocket 实现为线程,因为 .accept 方法已经在其构造函数中而不是在其运行方法中调用。因此,一旦我尝试创建线程,它就已经冻结了我的应用程序。

标签: java multithreading serversocket


【解决方案1】:

通常,我为此使用 N+1 个线程:一个用于 ServerSocket,以避免阻塞整个应用程序等待客户端连接;和 N 个线程来处理客户端的请求,N 是线程池的大小(我建议使用线程池而不是为每个客户端创建一个新线程)。

这是一个示例(只是编码,您可能希望有更好的异常管理等,但这是一个最小的工作示例)

public class Server {

    public static void main(String[] args) {
        new Server().startServer();
    }

    public void startServer() {
        final ExecutorService clientProcessingPool = Executors.newFixedThreadPool(10);

        Runnable serverTask = new Runnable() {
            @Override
            public void run() {
                try {
                    ServerSocket serverSocket = new ServerSocket(8000);
                    System.out.println("Waiting for clients to connect...");
                    while (true) {
                        Socket clientSocket = serverSocket.accept();
                        clientProcessingPool.submit(new ClientTask(clientSocket));
                    }
                } catch (IOException e) {
                    System.err.println("Unable to process client request");
                    e.printStackTrace();
                }
            }
        };
        Thread serverThread = new Thread(serverTask);
        serverThread.start();

    }

    private class ClientTask implements Runnable {
        private final Socket clientSocket;

        private ClientTask(Socket clientSocket) {
            this.clientSocket = clientSocket;
        }

        @Override
        public void run() {
            System.out.println("Got a client !");

            // Do whatever required to process the client's request

            try {
                clientSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

【讨论】:

  • 使用线程池处理客户端,您如何处理与客户端之间的接收和发送数据?几周前我看到的一个解决方案是 Hanlder 也有 2 个线程,一个用于发送数据,一个用于接收数据。
  • 另外,关于这个主题的一个非常相似但更具描述性的看法,请参阅以下文章:http://tutorials.jenkov.com/java-multithreaded-servers/thread-pooled-server.html
  • 此代码无助于抵御拒绝服务攻击,其中accept 被攻击者阻止(或限制)。这样的攻击者会阻止您的服务器接受新客户端。
  • 现在已经是 2017 年了,在 Java 8 中你想使用 Lambda 而不是匿名函数:Runnable serverTask = () -> { /* code here */ }
猜你喜欢
  • 2016-04-23
  • 1970-01-01
  • 1970-01-01
  • 2016-02-02
  • 2021-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多