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

會(huì)在target目錄下生成jar包

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

運(yùn)行服務(wù)端
java -cp basics98-1.0-SNAPSHOT.jar com.xiaoxuzhu.ClientOneToManyServerFrame
運(yùn)行多個(gè)客戶端
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對(duì)象
private Socket socket; // 聲明Socket對(duì)象socket
private Vector<Socket> vector = new Vector<Socket>();// 用于存儲(chǔ)連接到服務(wù)器的客戶端套接字對(duì)象
public void createSocket() {
try {
server = new ServerSocket(9527);
while (true) {
ta_info.append("等待新客戶連接......\n");
socket = server.accept();// 創(chuàng)建套接字對(duì)象
vector.add(socket);// 將套接字對(duì)象添加到向量對(duì)象中
ta_info.append("客戶端連接成功。" + socket + "\n");
new ServerThread(socket).start();// 創(chuàng)建并啟動(dòng)線程對(duì)象
}
} 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)建輸入流對(duì)象
while (true) {
String info = in.readLine();// 讀取信息
for (Socket s : vector) {// 遍歷所有客戶端套接字對(duì)象
if (s != socket) {// 如果不是發(fā)送信息的套接字對(duì)象
PrintWriter out = new PrintWriter(s
.getOutputStream(), true);// 創(chuàng)建輸出流對(duì)象
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("客戶端一對(duì)多通信——服務(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;// 聲明輸出流對(duì)象
/**
* 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)建套接字對(duì)象
out = new PrintWriter(socket.getOutputStream(), true);// 創(chuàng)建輸出流對(duì)象
new ClientThread(socket).start();// 創(chuàng)建并啟動(dòng)線程對(duì)象
} 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)建輸入流對(duì)象
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("客戶端一對(duì)多通信——客戶端程序");
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ù)器啟動(dòng)

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

客戶端2接收到的信息

客戶端3接收到的信息

以上就是Java聊天室之實(shí)現(xiàn)客戶端群聊功能的詳細(xì)內(nèi)容,更多關(guān)于Java聊天室的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
利用SpringBoot和LiteFlow解鎖復(fù)雜流程
隨著業(yè)務(wù)的復(fù)雜化,企業(yè)需要更加高效、便捷地管理自己的業(yè)務(wù)流程,這就需要借助一些流程引擎實(shí)現(xiàn),今天,我們就來介紹一種基于Java語言開發(fā)的輕量級(jí)工作流引擎——LiteFlow,以及如何在Spring Boot框架中集成它,從而提高企業(yè)的工作效率和開發(fā)效率2023-06-06
Spring?Boot在啟動(dòng)時(shí)執(zhí)行一次的功能實(shí)現(xiàn)
這篇文章主要給大家介紹了關(guān)于Spring?Boot在啟動(dòng)時(shí)執(zhí)行一次的功能實(shí)現(xiàn),在實(shí)習(xí)過程中,有時(shí)候會(huì)遇到一些項(xiàng)目啟動(dòng)初始化的需求,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-08-08
使用Jenkins來構(gòu)建GIT+Maven項(xiàng)目的方法步驟
這篇文章主要介紹了使用Jenkins來構(gòu)建GIT+Maven項(xiàng)目,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01
如何基于JWT實(shí)現(xiàn)接口的授權(quán)訪問詳解
授權(quán)是最常見的JWT使用場(chǎng)景,下面這篇文章主要給大家介紹了關(guān)于如何基于JWT實(shí)現(xiàn)接口的授權(quán)訪問的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-02-02

