【问题标题】:Multiple sockets cause ConnectException: Connection refused: connect多个套接字导致 ConnectException:连接被拒绝:连接
【发布时间】:2012-04-16 21:24:35
【问题描述】:

我正在 Windows XP 上的 Eclipse 中编程 java。我有一个多进程模拟,它使用 ProcessBuilder 来运行一个服务器和两个客户端。服务器启动一个线程来监听两个不同的套接字 - 每个客户端一个。我可以注释掉每个客户的代码,让其他的工作完美无缺。当我尝试同时运行它们时,一个客户端总是会出现 ConnectException 错误:连接被拒绝:连接。它似乎是哪个客户端运行速度较慢,尽管很难说。我可以在启动服务器之后但在客户端之前暂停,并且 netstat 验证两个套接字都处于活动状态。这可能是什么原因造成的?我在下面有一些简化的代码。

更新:基于 cmets,我已经编辑了代码以在单个套接字上对服务器进行多线程处理,但我仍然遇到同样的问题。下面的代码反映了这些变化。似乎套接字正在由一个客户端打开和关闭,然后另一个客户端有机会打开它。我可以在每个客户端结束时抛出暂停语句,让另一个客户端完成,但这是一个修复,而不是解决方案。所以现在真正的问题是,我如何让 ServerSocket 一直监听直到我指示它关闭?

服务器

try{
    server = new ServerSocket(sockNum); 
} catch (IOException e) {
        System.out.printf("Could not listen on port %d\n",sockNum);
        System.exit(-1);
}
while(true){
    ClientWorker w;
    try{
        Socket connection = server.accept();
        w = new ClientWorker(connection);
        Thread t = new Thread(w);
        t.start();
    } catch (IOException e) {
        System.out.printf("Accept failed: %d\n",sockNum);
        System.exit(-1);
    }
}

class ClientWorker implements Runnable {
    private Socket client;

          ClientWorker(Socket client) {
           this.client = client;
          }

          public void run(){
            Object line;
            ObjectInputStream in = null;
            PrintWriter out = null;
            try{
              in = new ObjectInputStream(client.getInputStream());
              out = new PrintWriter(client.getOutputStream(), true);
            } catch (IOException e) {
              System.out.println("in or out failed");
              System.exit(-1);
            }

            while(true){
                try{
                    line = in.readObject();
                    //Send data back to client
                    out.println("Sent from broker");
                    if(line instanceof String)
                        System.out.println(line);
                    else
                        System.out.println(line.getClass());                        
                } catch (IOException e) {
                    System.out.println("Read failed");
                    System.exit(-1);
                } catch (ClassNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }

客户

 try{
    socket = new Socket("localhost", socketNum);
    out = new ObjectOutputStream(socket.getOutputStream());
    in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

    out.writeObject(message);
    String line = in.readLine();
    System.out.println(line);
    } catch (UnknownHostException e) {
        System.out.println("Unknown host: localhost.eng");
        System.exit(1);
    } catch  (IOException e) {
        System.out.println("No I/O");
        System.exit(1);
    }

控制器

ProcessBuilder server = new ProcessBuilder("java.exe","-Xss64m","-cp","bin;jscheme.jar","ServerProcess");
server.redirectErrorStream(true);
Process runServer = server.start();

ProcessBuilder clientA = new ProcessBuilder("java.exe","-Xss64m","-cp","bin;jscheme.jar","ClientAProcess");
clientA.redirectErrorStream(true);
Process runClientA = clientA.start();

ProcessBuilder clientB = new ProcessBuilder("java.exe","-Xss64m","-cp","bin;jscheme.jar","ClientBProcess");
clientB.redirectErrorStream(true);
Process runClientB = clientB.start();

【问题讨论】:

    标签: java multithreading sockets multiprocessing connectexception


    【解决方案1】:

    '服务器启动一个线程来监听两个不同的套接字——每个客户端一个。'

    不,请不要这样做!为每个客户端分配单独的侦听套接字是不正常的设计。只需启动两个客户端都连接的一个侦听线程。当 accept() 返回时,为该客户端启动一个读取线程,传递由 accept() 调用返回的 ServerClient Socket。

    【讨论】:

    • 我改用多线程单套接字方法,但仍然遇到问题。有关更多信息,请参阅上面的更新。
    • 您的套接字代码现在看起来更好了。从客户端读取消息后,客户端是否从服务器打印“从代理发送”?客户端的循环在哪里?如果没有循环,客户端会不会只是退出并关闭连接?
    【解决方案2】:

    编写服务器的常用方法是在一个循环中侦听单个套接字。

    对于每个传入的连接,产生一个线程来处理客户端,然后立即在同一个服务器套接字上再次执行listen

    在您的情况下,如果两个客户端尝试连接到同一个服务器端口,第二个客户端总是会得到“连接被拒绝”。第一个客户端获取连接,服务器不会在套接字上重新发出listen。你还没有展示客户端如何获取他们的端口号,但我猜他们都试图连接到同一个端口。

    【讨论】:

    • 我改用多线程单套接字方法,但仍然遇到问题。有关更多信息,请参阅上面的更新。
    【解决方案3】:

    在我写这篇文章时,您的代码看起来不错。你有一个 ServerSocket 来监听新的连接。每个连接在发生时都会设置一个新线程来处理它并且给它自己的Socket。您的 Socket 和它们的线程应该是完全独立的。每个人的命运都应该完全独立于另一个人。他们不应该知道彼此的存在。

    弄清楚它们如何相互作用并将它们分开。

    尝试设置 100 个客户端而不是 2 个。这可能会使问题更加明显;一吨 TNT 会留下比鞭炮更大的火山口。

    另一个可能的问题:确保定期重置 ObjectOutputStream。这种 I/O 非常方便,但它可以做非常 奇怪的事情。如果没有重置,如果你发送同一个对象两次,第二次它只会发送一个对第一个版本的引用,如果最新版本发生了变化,这是没有用的。此外,即使 with 重置,如果您发送一个引用另一个对象的对象,that 对象也将被发送。 (这可能非常好。您可以发送一个引用包含数百万个对象的庞大结构的单个对象,整个事物将被发送保留其组织。它很巧妙而且非常有用,如果你知道它在做什么。)

    【讨论】:

      【解决方案4】:

      来自 OP

      所以在解决我认为不相关的问题的过程中,我似乎已经解决了最初的问题。我添加了两个主要内容。首先,我将客户端设置为在完成时发送“结束”命令,以便在尝试 readObject() 时套接字不会阻塞。其次,(我认为这是修复它的原因),我为 ServerSocket 定义了一个超时值,而不是让它未定义(又名无限)。当我在让事情正常工作后回去清理我的代码时,我尝试删除客户端进程中的暂停,但事情仍然有效!我的猜测是,在没有定义超时的情况下,当一个套接字在另一个套接字打开之前关闭时,ServerSocket 也会关闭。定义超时后,ServerSocket 将等到超时后再关闭。 (不过这只是猜测。)

      这是当前的工作代码。如果您认为修复的原因不同,请随时发表评论。

      服务器

      try{
          server = new ServerSocket(sockNum);
          server.setSoTimeout(timeOut);
      } catch (IOException e) {
          System.out.printf("Could not listen on port %d\n",sockNum);
          System.exit(-1);
      }
      
      while(isActive){
          ClientWorker w;
          try{
              Socket connection = server.accept();
              w = new ClientWorker(connection);
              Thread t = new Thread(w);
              t.start();
          } catch (IOException e) {
              if(e instanceof SocketTimeoutException)
                  isActive = false;
              else{
                  System.out.printf("Accept failed: %d\n",sockNum);
                  System.exit(-1);
              }
          }
      }
      
       class ClientWorker implements Runnable {
              private Socket client;
              private Source source = Source.NONE;
              private String sourceName = "?";
              private Boolean threadActive = true;
      
              ClientWorker(Socket client) {
                  this.client = client;
              }
      
              public void run(){
                  Object line;
                  ObjectInputStream in = null;
                  PrintWriter out = null;
                  try{
                      in = new ObjectInputStream(client.getInputStream());
                      out = new PrintWriter(client.getOutputStream(), true);
                  } catch (IOException e) {
                      System.out.println("in or out failed");
                      System.exit(-1);
                  }
      
                  while(threadActive){
                      try{
                          line = in.readObject();
                          if(line instanceof String){
                              if(line.equals("end")){
                                  threadActive = false;
                              }else
                                  sourceName = line;
                              }
                          } else 
                              handleData;
                      } catch (IOException e) {
                          System.out.println("Read failed");
                          threadActive = false;
                      } catch (ClassNotFoundException e) {
                          e.printStackTrace();
                          threadActive = false;
                      }
                  }
                  try {
                      this.client.close();
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
              }
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-03-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多