1. 程式人生 > >java服務端對多個客戶端的群聊功能程式碼實現

java服務端對多個客戶端的群聊功能程式碼實現

以下程式碼可以實現服務端傳送一條訊息,多個客戶端可以同時收到這條訊息,同時客戶端可以單獨的和服務端通訊
需要注意的是,此時服務端只需要一個傳送訊息的程序

服務端程式碼:

/**
 * 實現多個客戶端對應一個服務端進行通訊
 * 
 * @author wangjue
 *
 */
public class MyServer {
    private ArrayList<Socket> list = new ArrayList<Socket>();
    public static void main(String[] args) {

        MyServer ms = new
MyServer(); ms.initServer(10010); } public void initServer(int port) { try { ServerSocket server = new ServerSocket(port); System.out.println("服務端正等待客戶端連線..."); /* * 啟動發訊息的執行緒 * 因為是一個服務端對應多個客戶端,因此傳送訊息的執行緒只需要一個,不需要隨著客戶端的個數增加而增加 */
SendThread st = new SendThread(list); new Thread(st).start(); // 表示可以連線多個客戶端 while (true) { Socket socket = server.accept(); list.add(socket); System.out.println("已經有一個客戶端連線上來了..."); //啟動收訊息的執行緒
RecieveThread rt = new RecieveThread(socket); new Thread(rt).start(); } } catch (IOException e) { e.printStackTrace(); } } }
/**
 * 接收客戶端不斷傳來訊息的執行緒
 * 
 * @author wangjue
 *
 */
public class RecieveThread implements Runnable {
    private Socket socket;
    private String recieveMsg;
    public RecieveThread(Socket socket) {
        this.socket = socket;
    }
    public String getRecieveMsg() {
        return recieveMsg;
    }


    @Override
    public void run() {
        try {
            InputStream ips = socket.getInputStream();
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            while (true) {
                int t = ips.read();
                // 收到換行符為止
                while (t != '\n') {
                    bos.write(t);
                    t = ips.read();
                }
                byte[] b = bos.toByteArray();
                recieveMsg = new String(b);
                System.out.println(recieveMsg);
                bos.reset();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}
/**
 * 傳送訊息給多個客戶端的執行緒
 * @author wangjue
 *
 */
public class SendThread implements Runnable {
    private ArrayList<Socket> list;
    public SendThread(ArrayList<Socket> list) {
        this.list = list;
    }
    @Override
    public void run() {
        try {
            while (true) {
                //wait for scanner input,scanner是阻塞性,若沒有輸出內容,程式碼會停止不往下執行
                Scanner sc = new Scanner(System.in);            
                String msg = "服務端說:" + sc.nextLine() + "----" + new Date(System.currentTimeMillis()) + "\n";
                //通過for迴圈依次取出所有已經連上的socket物件,將服務端發出的訊息寫到輸入流
                for (int i = 0; i < list.size(); i++) {
                    OutputStream ops = list.get(i).getOutputStream();
                    ops.write(msg.getBytes());
                    ops.flush();
                }                           
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

客戶端程式碼

public class MyClient {
    public static void main(String[] args) {
        MyClient mc = new MyClient();
        mc.initClient("127.0.0.1", 10010);

    }
    public void initClient(String host, int port) {
        try {
            Socket socket = new Socket(host, port);
            talkUI ui = new talkUI();
            ui.initUI();            
            // 啟動收訊息的執行緒
            RecieveThread rt = new RecieveThread(socket, ui);
            new Thread(rt).start();
            // 啟動發訊息的執行緒
            SendThread st = new SendThread(socket, ui);
            new Thread(st).start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
/**
 * 接收服務端傳來的訊息並顯示在面板
 * @author wangjue
 *
 */

public class RecieveThread implements Runnable {
    private Socket socket;
    private talkUI ui;//傳入面板物件,呼叫getArea1方法獲取area1物件
    public RecieveThread(Socket socket,talkUI ui) {
        this.socket = socket;
        this.ui = ui;
    }

    @Override
    public void run() {
        try {
            InputStream ips = socket.getInputStream();
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            while (true) {
                int t = ips.read();
                while (t != '\n') {
                    bos.write(t);
                    t = ips.read();
                }
                byte[] b = bos.toByteArray();
                //收到服務端傳來的訊息
                String msg = new String(b);
                //將訊息顯示在訊息面板上
                ui.getArea1().append(msg+"\n"); 
                //將服務端的訊息接收到並顯示在面板後,清空輸入流,下次收到訊息後就不會顯示上次已經收到的訊息
                bos.reset();

            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}
/**
 * 向服務端傳送訊息
 * @author wangjue
 *
 */
public class SendThread implements Runnable {
    private Socket socket;
    private talkUI ui; 
    public SendThread(Socket socket, talkUI ui) {
        this.socket = socket;
        this.ui = ui;
    }
    @Override
    public void run() {
        try {
            ui.ops = socket.getOutputStream();          
            while (true) {
                if(ui.sendMsg2!=null){
                    byte[] b = ui.sendMsg2.getBytes();
                    ui.ops.write(b);
                    ui.ops.flush();             
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
/**
 * 聊天面板
 * @author wangjue
 *
 */

public class talkUI implements ActionListener{
    private JTextArea area1 = new JTextArea(15,30);
    private JTextArea area2 = new JTextArea(10,30);
    public OutputStream ops;
    //在對話方塊輸入的內容
    private String sendMsg;
    //傳給服務端的內容
    public String sendMsg2;

    public JTextArea getArea1() {
        return area1;
    }
    public void initUI() {
         JFrame jf = new JFrame();
         jf.setTitle("私人聊天室");
         jf.setSize(400,600);
         FlowLayout layout = new FlowLayout();
         jf.setLayout(layout);
         //顯示面板

         area1.setEditable(false);
         jf.add(area1);
         //輸入面板

         jf.add(area2);
         //傳送按鈕
         JButton btn = new JButton("傳送");
         jf.add(btn);
         jf.setDefaultCloseOperation(3);
         jf.setVisible(true);
         btn.addActionListener(this);
     }
    @Override
    public void actionPerformed(ActionEvent e) {
        sendMsg  = area2.getText();
        sendMsg2 = sendMsg+"\n"; //傳給服務端的訊息要加入換行符,服務端才能知道什麼時候結束接收
        //輸入的內容要顯示在面板上
        area1.append("自己說:"+sendMsg+"----"+new Date(System.currentTimeMillis())+"\n");
        //點擊發送後,輸入面板要清空
        area2.setText("");
        //要每點選一次傳送就要將內容寫入輸出流中
        try {
            ops.write(sendMsg2.getBytes());         
        } catch (IOException e1) {
            e1.printStackTrace();
        }       
    }
}

結果顯示
這裡寫圖片描述