You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 16:52:15