架構概覽
- Server:
ServerSocket 監聽端口,維護 List<Socket> 所有客戶端連接,每連接啟動 HandleSocket 線程處理收發。
- Client:
Socket 連接服務器,雙線程:ClientSend 讀控制台發送,ClientReceive 讀網絡流打印。
服務端代碼
public class Server {
public static void main(String[] args) throws IOException {
List<Socket> clients = new ArrayList<>();
ServerSocket server = new ServerSocket(10000);
while (true) {
Socket socket = server.accept();
synchronized (clients) { clients.add(socket); }
new HandleSocket(socket, clients).start();
}
}
}
class HandleSocket extends Thread {
private Socket socket; private List<Socket> list;
public HandleSocket(Socket s, List<Socket> l) { this.socket = s; this.list = l; }
public void run() {
String ip = socket.getInetAddress().getHostAddress();
System.out.println(ip + " 上線");
if ("192.168.1.117".equals(ip)) { // 黑名單示例
synchronized (list) { sendAll(ip + " 被拉黑"); list.remove(socket); }
return;
}
try (BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "GBK"))) {
String msg;
while ((msg = br.readLine()) != null) {
String broadcast = ip + ":" + msg;
System.out.println(broadcast);
sendAll(broadcast);
}
} catch (IOException e) {
System.out.println(ip + " 下線");
synchronized (list) { list.remove(socket); }
}
}
private void sendAll(String msg) {
synchronized (list) {
for (Socket s : list) if (s != socket) {
try { new PrintStream(s.getOutputStream()).println(msg); }
catch (IOException ignored) {}
}
}
}
}
客戶端代碼
public class Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("192.168.1.188", 10000);
new ClientSend(socket).start();
new ClientReceive(socket).start();
}
}
class ClientSend extends Thread {
private Socket socket;
public ClientSend(Socket s) { this.socket = s; }
public void run() {
try (PrintStream ps = new PrintStream(socket.getOutputStream());
Scanner sc = new Scanner(System.in)) {
while (sc.hasNextLine()) ps.println(sc.nextLine());
} catch (IOException ignored) {}
}
}
class ClientReceive extends Thread {
private Socket socket;
public ClientReceive(Socket s) { this.socket = s; }
public void run() {
try (BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
String line;
while ((line = br.readLine()) != null) System.out.println(line);
} catch (IOException ignored) {}
}
}
運行順序
- 先啟動
Server.main。
- 再啟動多個
Client.main(修改 IP 為服務器地址)。
- 控制台輸入即發送,所有客戶端同步顯示。
改進方向
- 用戶名登錄、私聊、表情、文件傳輸。
- Netty 重寫實現高併發、心跳、編解碼器。
- GUI 界面(Swing/JavaFX)替換控制台。