多个套接字导致ConnectException:连接被拒绝:连接

我在Windows XP上用Eclipse编程java。 我有一个多进程模拟,它使用ProcessBuilder来运行服务器和两个客户端。 服务器启动一个线程来侦听两个不同的套接字 – 每个客户端一个。 我可以为每个客户注释掉代码,让其他工作完全正常。 当我尝试同时运行它们时,一个客户端将始终使用ConnectException错误:连接被拒绝:连接。 它似乎是哪个客户端运行速度较慢,但​​很难说。 我可以在启动服务器之后但在客户端之前暂停,netstatvalidation两个套接字都处于活动状态。 可能是什么导致了这个? 我在下面有一些简化的代码。

更新:根据评论,我编辑了代码以在单个套接字上multithreading服务器,但我仍然遇到同样的问题。 下面的代码反映了这些变化。 看来套接字是由一个客户端打开和关闭,然后另一个客户端有机会打开它。 我可以在每个客户端的末尾抛出暂停语句,允许另一个完成,但这是一个修复,而不是解决方案。 所以现在真正的问题是,在指示它关闭之前,如何保持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(); 

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

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

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

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

在您的情况下,如果两个客户端尝试连接到同一服务器端口,则第二个客户端将始终获得“连接被拒绝”。 第一个客户端获取连接,服务器不会重新发出listen套接字。 您尚未显示客户端如何获取其端口号,但我猜他们都在尝试连接到同一端口。

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

弄清楚他们如何互动并将它们分开。

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

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

来自OP

因此,在解决我认为不相关的问题的过程中,我似乎已经解决了最初的问题。 我添加了两件主要的事情。 首先,我设置客户端在完成时发送“end”命令,以便在尝试readObject()时套接字不会阻塞。 其次,(我认为这是修复它的原因),我为ServerSocket定义了一个超时值,而不是将其保留为undefined(也就是无限)。 在我开始工作之后我回去清理我的代码时,我尝试删除客户端进程中的暂停,但事情仍然有效! 我的猜测是,没有定义的超时,当一个套接字在另一个套接字打开之前关闭时,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(); } } }