Java聊天室之實現(xiàn)客戶端群聊功能
一、題目描述
題目實現(xiàn):不同的客戶端之間需要進行通信,一個客戶端與其他的多個客戶端進行通信,實現(xiàn)群聊功能。
實現(xiàn)一個客戶端與其他多個客戶端進行通信,運行程序,服務(wù)器啟動后,啟動3個客戶端程序,然后通過第一個客戶端向另外兩個客戶端發(fā)送信息,則另外的兩個客戶端都會收到服務(wù)器發(fā)送的信息。
二、解題思路
創(chuàng)建一個服務(wù)類:ClientOneToManyServerFrame,繼承JFrame類
定義一個createSocket()方法,用于創(chuàng)建服務(wù)Socket和監(jiān)聽客戶端程序。以及創(chuàng)建并啟動線程對象并將接收到的客戶端發(fā)送的信息轉(zhuǎn)發(fā)給其他客戶端。
創(chuàng)建一個客戶端類:ClientOneToManyClientFrame,繼承JFrame類
定義一個createClientSocket()方法,用于創(chuàng)建與服務(wù)器連接的Socket對象,輸出流對象,以及啟動線程對象接收服務(wù)器端轉(zhuǎn)發(fā)的信息。
技術(shù)重點:
在服務(wù)器端通過線程對客戶端發(fā)送的信息進行監(jiān)聽,當(dāng)有客戶端發(fā)送信息時,就會將該信息發(fā)送給其他已經(jīng)登錄到服務(wù)器的客戶端,但是不會向發(fā)送方發(fā)送該信息,在客戶端也通過線程來監(jiān)聽服務(wù)器轉(zhuǎn)發(fā)的信息。 (1)在服務(wù)器端創(chuàng)建線程類ServerThread,用于接收客戶端發(fā)送的信息,并轉(zhuǎn)發(fā)給其他已經(jīng)連接到服務(wù)器的客戶端。
(2)在客戶端創(chuàng)建線程類ClientThread,用于接收服務(wù)器端轉(zhuǎn)發(fā)的客戶端信息,并在客戶端的文本域中顯示接收到的信息。
啟動多個客戶端:
1、把項目打成jar包:利用maven 的clean install

會在target目錄下生成jar包

2、進入target目錄,使用java -cp的命令運行指定的類
java -cp 命令中 cp 指的就是classpath。使用該命令可以運行jar中的某個指定的類(要包含全路徑的包名)
進入cmd命令模式

運行服務(wù)端
java -cp basics98-1.0-SNAPSHOT.jar com.xiaoxuzhu.ClientOneToManyServerFrame
運行多個客戶端
java -cp basics98-1.0-SNAPSHOT.jar com.xiaoxuzhu.ClientOneToManyClientFrame
三、代碼詳解
ClientOneToManyServerFrame
package com.xiaoxuzhu;
import java.awt.BorderLayout;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
/**
* Description:
*
* @author xiaoxuzhu
* @version 1.0
*
* <pre>
* 修改記錄:
* 修改后版本 修改人 修改日期 修改內(nèi)容
* 2022/6/5.1 xiaoxuzhu 2022/6/5 Create
* </pre>
* @date 2022/6/5
*/
public class ClientOneToManyServerFrame extends JFrame {
private JTextArea ta_info;
private ServerSocket server; // 聲明ServerSocket對象
private Socket socket; // 聲明Socket對象socket
private Vector<Socket> vector = new Vector<Socket>();// 用于存儲連接到服務(wù)器的客戶端套接字對象
public void createSocket() {
try {
server = new ServerSocket(9527);
while (true) {
ta_info.append("等待新客戶連接......\n");
socket = server.accept();// 創(chuàng)建套接字對象
vector.add(socket);// 將套接字對象添加到向量對象中
ta_info.append("客戶端連接成功。" + socket + "\n");
new ServerThread(socket).start();// 創(chuàng)建并啟動線程對象
}
} catch (IOException e) {
e.printStackTrace();
}
}
class ServerThread extends Thread {
Socket socket;
public ServerThread(Socket socket) {
this.socket = socket;
}
public void run() {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));// 創(chuàng)建輸入流對象
while (true) {
String info = in.readLine();// 讀取信息
for (Socket s : vector) {// 遍歷所有客戶端套接字對象
if (s != socket) {// 如果不是發(fā)送信息的套接字對象
PrintWriter out = new PrintWriter(s
.getOutputStream(), true);// 創(chuàng)建輸出流對象
out.println(info);// 發(fā)送信息
out.flush();// 刷新輸出緩沖區(qū)
}
}
}
} catch (IOException e) {
ta_info.append(socket + "已經(jīng)退出。\n");
vector.remove(socket);// 移除退出的客戶端套接字
}
}
}
/**
* Launch the application
*
* @param args
*/
public static void main(String args[]) {
ClientOneToManyServerFrame frame = new ClientOneToManyServerFrame();
frame.setVisible(true);
frame.createSocket();
}
/**
* Create the frame
*/
public ClientOneToManyServerFrame() {
super();
setTitle("客戶端一對多通信——服務(wù)器端程序");
setBounds(100, 100, 385, 266);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JScrollPane scrollPane = new JScrollPane();
getContentPane().add(scrollPane, BorderLayout.CENTER);
ta_info = new JTextArea();
scrollPane.setViewportView(ta_info);
}
}
ClientOneToManyClientFrame
package com.xiaoxuzhu;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
/**
* Description:
*
* @author xiaoxuzhu
* @version 1.0
*
* <pre>
* 修改記錄:
* 修改后版本 修改人 修改日期 修改內(nèi)容
* 2022/6/5.1 xiaoxuzhu 2022/6/5 Create
* </pre>
* @date 2022/6/5
*/
public class ClientOneToManyClientFrame extends JFrame{
private JTextArea ta_info;
private JTextField tf_send;
PrintWriter out;// 聲明輸出流對象
/**
* Launch the application
*
* @param args
*/
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ClientOneToManyClientFrame frame = new ClientOneToManyClientFrame();
frame.setVisible(true);
frame.createClientSocket();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public void createClientSocket() {
try {
Socket socket = new Socket("127.0.0.1", 9527);// 創(chuàng)建套接字對象
out = new PrintWriter(socket.getOutputStream(), true);// 創(chuàng)建輸出流對象
new ClientThread(socket).start();// 創(chuàng)建并啟動線程對象
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
class ClientThread extends Thread {
Socket socket;
public ClientThread(Socket socket) {
this.socket = socket;
}
public void run() {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));// 創(chuàng)建輸入流對象
while (true) {
String info = in.readLine();// 讀取信息
ta_info.append(info + "\n");// 在文本域中顯示信息
if (info.equals("88")) {
break;// 結(jié)束線程
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void send() {
String info = tf_send.getText();// 獲得輸入的信息
if (info.equals("")) {
return;// 如果沒輸入信息則返回,即不發(fā)送
}
if (info.equals("88")) {
System.exit(0);// 如果沒輸入信息是88,則退出
}
out.println(info);// 發(fā)送信息
out.flush();// 刷新輸出緩沖區(qū)
tf_send.setText(null);// 清空文本框
}
/**
* Create the frame
*/
public ClientOneToManyClientFrame() {
super();
setTitle("客戶端一對多通信——客戶端程序");
setBounds(100, 100, 385, 266);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPanel panel = new JPanel();
getContentPane().add(panel, BorderLayout.SOUTH);
final JLabel label = new JLabel();
label.setText("輸入聊天內(nèi)容:");
panel.add(label);
tf_send = new JTextField();
tf_send.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
send();// 調(diào)用方法發(fā)送信息
}
});
tf_send.setPreferredSize(new Dimension(180, 25));
panel.add(tf_send);
final JButton button = new JButton();
button.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
send();// 調(diào)用方法發(fā)送信息
}
});
button.setText("發(fā) 送");
panel.add(button);
final JScrollPane scrollPane = new JScrollPane();
getContentPane().add(scrollPane, BorderLayout.CENTER);
ta_info = new JTextArea();
scrollPane.setViewportView(ta_info);
//
}
}服務(wù)器啟動

客戶端1向其他客戶端群發(fā)信息

客戶端2接收到的信息

客戶端3接收到的信息

以上就是Java聊天室之實現(xiàn)客戶端群聊功能的詳細內(nèi)容,更多關(guān)于Java聊天室的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解如何使用MongoDB+Springboot實現(xiàn)分布式ID的方法
這篇文章主要介紹了詳解如何使用MongoDB+Springboot實現(xiàn)分布式ID的方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
IDEA 當(dāng)前在線人數(shù)和歷史訪問量的示例代碼
這篇文章主要介紹了IDEA 當(dāng)前在線人數(shù)和歷史訪問量的實例代碼,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-08-08
SpringBoot+Redis防止惡意刷新與暴力請求接口的實現(xiàn)
這篇文章主要為大家介紹了如何利用springboot和Redis來實現(xiàn)防止惡意刷新與暴力請求接口,文中的示例代碼講解詳細,需要的可以參考一下2022-06-06
淺談MyBatisPlus中LocalDateTime引發(fā)的一些問題和解決辦法
MyBatisPlus進行數(shù)據(jù)庫操作時,我們經(jīng)常會遇到處理日期時間類型的需求,本文主要介紹了淺談MyBatisPlus中LocalDateTime引發(fā)的一些問題和解決辦法,具有一定的參考價值,感興趣的可以了解一下2024-07-07

