Java服务器无法接受多客户端请求问题排查求助
问题
为什么我的Java服务器程序在多次运行客户端时无法再接受新客户端?
即使运行多个客户端,服务器终端仅打印一次"A new Client has joined"。我期望服务器能接受多客户端请求,通过不同线程处理,且每运行一次客户端就打印一次该提示。
Server.java代码
import java.net.*; public class Server { public static void main(String []args)throws Exception { ServerSocket ss=new ServerSocket(9090); while (true) { System.out.println("Looking for connections"); Socket soc=ss.accept(); System.out.println("A new Client has joined"); ClientHandler ch=new ClientHandler(soc); Thread t1=new Thread(ch); t1.start(); } } }
ClientHandler.java代码
import java.io.*; import java.net.*; import java.util.ArrayList; public class ClientHandler implements Runnable { Socket soc; String username; BufferedReader br; PrintWriter out; static ArrayList<ClientHandler> clients=new ArrayList<>(); ClientHandler(Socket soc) { this.soc=soc; try { this.br=new BufferedReader(new InputStreamReader(soc.getInputStream())); this.out=new PrintWriter(soc.getOutputStream(),true); this.username=br.readLine(); broadcast(username + " has joined the group chat"); clients.add(this); } catch(Exception e ){e.printStackTrace();} } public void run() { while (true) { try{ String message=br.readLine(); broadcast(message); }catch(Exception e ){e.printStackTrace();break;} } } void broadcast(String message) { for (ClientHandler c : clients) c.out.println(message); } }
Client.java代码
import java.net.*; import java.util.*; public class Client { public static void main(String []args)throws Exception { Socket soc=new Socket("localhost",9090); String username; Scanner sc=new Scanner(System.in); System.out.println("Please enter your username"); username=sc.nextLine(); ClientRead cr=new ClientRead(soc,username); ClientWrite cw=new ClientWrite(soc,username); Thread t1=new Thread(cr); Thread t2=new Thread(cw); t1.start(); t2.start(); sc.close(); } }
解决方法
核心问题1:服务器主线程被阻塞
你的ClientHandler构造函数里调用了br.readLine(),这是阻塞操作——如果客户端未发送数据,服务器主线程会一直停在这里,无法回到循环执行ss.accept()接受新客户端连接。
修复:
把读取用户名的逻辑从构造函数移到run()方法,确保主线程能立刻回到循环继续监听新连接:
public class ClientHandler implements Runnable { Socket soc; String username; BufferedReader br; PrintWriter out; static ArrayList<ClientHandler> clients=new ArrayList<>(); ClientHandler(Socket soc) { this.soc=soc; try { this.br=new BufferedReader(new InputStreamReader(soc.getInputStream())); this.out=new PrintWriter(soc.getOutputStream(),true); // 移除构造函数中的读取操作 } catch(Exception e ){e.printStackTrace();} } public void run() { try{ // 在run方法中读取用户名 this.username=br.readLine(); broadcast(username + " has joined the group chat"); clients.add(this); while (true) { String message=br.readLine(); if(message == null) break; // 处理客户端主动断开的情况 broadcast(message); } }catch(Exception e ){ e.printStackTrace(); }finally{ // 客户端断开后清理资源并移除列表项 clients.remove(this); try { soc.close(); } catch (IOException e) { e.printStackTrace(); } } } void broadcast(String message) { synchronized(clients){ // 加锁避免并发修改异常 for (ClientHandler c : clients) c.out.println(message); } } }
核心问题2:客户端未发送用户名
你的Client代码仅创建了ClientRead和ClientWrite类,但未实现发送用户名的逻辑。客户端需要在输入用户名后立刻将其发送给服务器,否则服务器的br.readLine()会一直阻塞。
补充ClientWrite和ClientRead的完整实现:
// ClientWrite.java import java.io.*; import java.net.*; import java.util.*; public class ClientWrite implements Runnable { Socket soc; String username; PrintWriter out; Scanner sc; public ClientWrite(Socket soc, String username) { this.soc = soc; this.username = username; try { this.out = new PrintWriter(soc.getOutputStream(), true); this.sc = new Scanner(System.in); // 连接成功后立即发送用户名到服务器 out.println(username); } catch (IOException e) { e.printStackTrace(); } } @Override public void run() { while (true) { String message = sc.nextLine(); out.println(username + ": " + message); } } } // ClientRead.java import java.io.*; import java.net.*; public class ClientRead implements Runnable { Socket soc; BufferedReader br; public ClientRead(Socket soc, String username) { this.soc = soc; try { this.br = new BufferedReader(new InputStreamReader(soc.getInputStream())); } catch (IOException e) { e.printStackTrace(); } } @Override public void run() { String message; try { while ((message = br.readLine()) != null) { System.out.println(message); } } catch (IOException e) { e.printStackTrace(); } } }
额外优化说明
- 给
clients列表的遍历操作加锁,避免多线程并发修改导致的ConcurrentModificationException。 - 在客户端断开连接时,从
clients列表移除对应实例并关闭Socket,避免资源泄漏。
内容的提问来源于stack exchange,提问作者Khoka420
相关产品推荐
相关产品推荐

