首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java Socket 實作多執行緒聊天室完整範例

     編輯:Java 相關知識

前言

近期深入研究 Java Socket 網路通訊基礎,動手實作一個支援多用戶同時線上聊天的即時通訊室。這裡將完整的專案架構、核心程式碼與執行步驟分享給有興趣的開發者參考,希望能幫助大家快速掌握 Socket 程式設計的精髓。

專案目錄結構

專案採用標準 Maven 結構,主要分為客戶端與伺服器端兩大模組:

專案目錄結構圖

核心程式碼解析

1. 聊天客戶端 - ChatClient

客戶端採用 AWT 圖形介面,包含訊息顯示區、輸入框,並使用獨立執行緒持續監聽伺服器推送的訊息。

package com.panda.chat;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;

@SuppressWarnings("serial")
public class ChatClient extends Frame {
    private TextArea ta = new TextArea();
    private TextField tf = new TextField();
    private DataOutputStream dos = null;
    private DataInputStream dis = null;
    private Socket socket = null;
    private boolean bConnected = false;
    private Thread thread = null;

    public static void main(String[] args) {
        new ChatClient().frameClient();
    }

    public void frameClient() {
        setSize(400, 400);
        setLocation(400, 300);
        add(ta, BorderLayout.NORTH);
        add(tf, BorderLayout.SOUTH);
        pack();

        tf.addActionListener(new TfListener());
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                disconnected();
                System.exit(0);
            }
        });

        this.connect();
        setVisible(true);
    }

    private void connect() {
        try {
            socket = new Socket("127.0.0.1", 8888);
            thread = new Thread(new ChatThread());
            thread.start();
            dos = new DataOutputStream(socket.getOutputStream());
            dis = new DataInputStream(socket.getInputStream());
        } catch (UnknownHostException | IOException e) {
            e.printStackTrace();
        }
    }

    private void disconnected() {
        bConnected = false;
        try {
            if (dos != null) dos.close();
            if (dis != null) dis.close();
            if (socket != null) socket.close();
        } catch (IOException e1) {
            e1.printStackTrace();
        }
    }

    private class TfListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            String strMsg = tf.getText();
            tf.setText("");
            try {
                dos.writeUTF(strMsg);
                dos.flush();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
    }

    private class ChatThread implements Runnable {
        @Override
        public void run() {
            try {
                bConnected = true;
                while (bConnected) {
                    String msg = dis.readUTF();
                    ta.setText(ta.getText() + msg + "\n");
                }
            } catch (SocketException e) {
                System.out.println("連線中斷");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

2. 聊天伺服器 - ChatServer

伺服器端使用 ServerSocket 監聽連線,每當有新客戶端接入,即啟動一條獨立執行緒處理該客戶的收發訊息,並將收到的訊息廣播給所有已連線的客戶端。

package com.panda.chat;

import java.io.*;
import java.net.*;
import java.util.*;

public class ChatServer {
    private boolean started = false;
    private List chatThreads = new ArrayList<>();

    public static void main(String[] args) {
        new ChatServer().startServer();
    }

    private void startServer() {
        try (ServerSocket seso = new ServerSocket(8888)) {
            started = true;
            System.out.println("伺服器已啟動,等待客戶端連線...");

            while (started) {
                Socket sos = seso.accept();
                System.out.println("一個客戶端已連線:" + sos.getInetAddress());

                ChatThread ct = new ChatThread(sos);
                chatThreads.add(ct);
                new Thread(ct).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private class ChatThread implements Runnable {
        private Socket socket;
        private DataInputStream din = null;
        private DataOutputStream don = null;
        private boolean bConnected = false;

        public ChatThread(Socket socket) {
            this.socket = socket;
        }

        private void send(String strMsgIn) {
            try {
                don.writeUTF(strMsgIn);
                don.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void run() {
            try {
                din = new DataInputStream(socket.getInputStream());
                don = new DataOutputStream(socket.getOutputStream());

                bConnected = true;
                while (bConnected) {
                    String strMsgIn = din.readUTF();
                    System.out.println("收到訊息:" + strMsgIn);

                    for (ChatThread ct : chatThreads) {
                        ct.send(strMsgIn);
                    }
                }
            } catch (IOException e) {
                try {
                    socket.close();
                    chatThreads.remove(this);
                    System.out.println("客戶端斷開連線,移除執行緒");
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            } finally {
                try {
                    if (din != null) din.close();
                    if (don != null) don.close();
                    if (socket != null) socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

執行與測試

  1. 先啟動 ChatServer 主程式,控制台將顯示「伺服器已啟動...」。
  2. 接著多次執行 ChatClient 主程式,每次啟動都會彈出一個聊天視窗。
  3. 在任一視窗的輸入框輸入文字並按 Enter,訊息即會即時廣播到所有開啟的客戶端視窗中。

多客戶端聊天測試截圖

關鍵技術點總結

  • Socket 通訊:採用 TCP 協議,透過 Socket 與 ServerSocket 建立可靠的雙向連線。
  • 多執行緒模型:伺服器為每個客戶端分配獨立執行緒(ChatThread),實現並發處理;客戶端另闢執行緒非阻塞接收訊息。
  • 資料流處理:使用 DataOutputStream/DataInputStream 進行 UTF-8 字串的高效讀寫。
  • 廣播機制:伺服器維護一個執行緒集合,收到訊息時遍歷集合逐一轉發。
  • 資源釋放:在 finally 區塊或 try-with-resources 中確保關閉串流與 Socket,避免洩漏。

延伸思考與改進方向

此範例為教學示範用途,實際生產環境可考慮:

  • 引入 NIO(Selector)替代傳統 BIO,提升併發承載能力。
  • 加入心跳機制檢測死連線,自動清理失效執行緒。
  • 設計通訊協定(如 JSON/Protobuf),支援私聊、群組、檔案傳輸等豐富功能。
  • 整合資料庫持久化聊天記錄,實現離線訊息推送。

完整原始碼可依照上述結構自行建立專案,若在實作過程中遇到任何問題,歡迎留言交流探討。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved