【java IO流项目】实现多人实时聊天室,需连接同一WiFi
想要完成這個項目的前提條件
①多個人連接同一WiFi在局域網里,所有人關閉防火墻,就使用中的,不會就關閉所有
②指定一個人為服務端?,這個人去命令行ipconfig查看自己的ipv4
這是我win11虛擬機的ip? ?記住它,把他作為服務端ip
本次測試虛擬機就是別人電腦,上課6人互連成功的,宿舍沒人合作,用虛擬機代替
這個在虛擬機開啟服務端具體見下面測試1
這個在自己電腦開啟服務端具體見下面測試2
?寫服務端
完成的結構
先寫一個DateUtil類獲取每次發送信息的系統時間
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateUtil {
? ? public static final SimpleDateFormat SDF =
? ? ? ? ? ? new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
? ? public static String date2String(Date date){
? ? ? ? return SDF.format(date);
? ? }
? ? public static Date string2Date(String dateStr){
? ? ? ? try {
? ? ? ? ? ? return SDF.parse(dateStr);
? ? ? ? } catch (ParseException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? return null;
? ? ? ? }
? ? }
}
再寫一個Message類獲取發送人昵稱,發送信息內容,以及發送時間
import java.io.Serializable;
// 消息對象類
public class Message implements Serializable {
? ? private static final long serialVersionUID = -6849794470754667710L;
? ? private String message;// 消息內容
? ? private String name;// 發送人
? ? private String date;// 發送時間
? ? @Override
? ? public String toString() { // 用Generate功能自動生成toString方法的重寫
? ? ? ? return "Message{" +
? ? ? ? ? ? ? ? "message='" + message + '\'' +
? ? ? ? ? ? ? ? ", name='" + name + '\'' +
? ? ? ? ? ? ? ? ", date='" + date + '\'' +
? ? ? ? ? ? ? ? '}';
? ? }
? ? public Message() {
? ? }
? ? public Message(String message, String name, String date) {
? ? ? ? this.message = message;
? ? ? ? this.name = name;
? ? ? ? this.date = date;
? ? }
? ? public String getMessage() {
? ? ? ? return message;
? ? }
? ? public void setMessage(String message) {
? ? ? ? this.message = message;
? ? }
? ? public String getName() {
? ? ? ? return name;
? ? }
? ? public void setName(String name) {
? ? ? ? this.name = name;
? ? }
? ? public String getDate() {
? ? ? ? return date;
? ? }
? ? public void setDate(String date) {
? ? ? ? this.date = date;
? ? }
}
最后寫服務端Server類代碼
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class Server {
? ? // server.accept()返回的socket代表一個客戶端對象
? ? // 這里定義一個List存儲所有的客戶端socket對象
? ? // 考慮到廣播消息的時候存在多線程并發共享一個List的問題, 使用CopyOnWriteArrayList線程安全類
? ? static List<Socket> socketList = new CopyOnWriteArrayList<>();
? ? public static void main(String[] args) {
? ? ? ? // 服務端server
? ? ? ? ServerSocket server = null;
? ? ? ? try {
? ? ? ? ? ? // 初始化服務端server對象, 監聽8080端口下面改成8081因為我的8080端口占用了
? ? ? ? ? ? server = new ServerSocket(8081);
? ? ? ? ? ? System.out.println("服務端啟動成功, 等待客戶端接入");
? ? ? ? ? ? while (true){// 在主線程中循環接收客戶端的接入
? ? ? ? ? ? ? ? Socket socket = server.accept();
? ? ? ? ? ? ? ? // 每接入到一個客戶端socket對象, 將socket對象存儲到List中
? ? ? ? ? ? ? ? socketList.add(socket);
? ? ? ? ? ? ? ? System.out.println("客戶端IP:" + socket.getInetAddress().getHostAddress() + "進入聊天室, 當前聊天室socket數: " + socketList.size());
? ? ? ? ? ? ? ? // 為每個客戶端socket開辟一個子線程, 來接收客戶端消息和廣播消息, 把socket對象傳給子線程
? ? ? ? ? ? ? ? // 服務端會存在多個子線程對象, 每個子線程對象負責接收對應的客戶端消息
? ? ? ? ? ? ? ? new ReceiveMessageThread(socket).start();
? ? ? ? ? ? }
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? }
? ? // 接收消息并廣播給所有客戶端的子線程靜態內部類, 繼承Thread類, 重寫run方法
? ? private static class ReceiveMessageThread extends Thread{
? ? ? ? Socket socket;// 子線程socket成員變量
? ? ? ? // 子線程構造方法, 主線程通過參數中傳入socket
? ? ? ? public ReceiveMessageThread(Socket socket) {
? ? ? ? ? ? this.socket = socket;
? ? ? ? }
? ? ? ? @Override
? ? ? ? public void run() {
? ? ? ? ? ? while (true) { // 循環接收客戶端的輸入
? ? ? ? ? ? ? ? ObjectInputStream ois = null;// 對象輸入流
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? // 用socket底層的字節輸入流包裝為對象輸入流
? ? ? ? ? ? ? ? ? ? ois = new ObjectInputStream(socket.getInputStream());
? ? ? ? ? ? ? ? ? ? // 讀客戶端發送的對象, 如果客戶端沒有發送, 此處會等待, 客戶端發送后, 對象輸入流可以讀取到, 并反序列化
? ? ? ? ? ? ? ? ? ? Message msg = (Message) ois.readObject();
? ? ? ? ? ? ? ? ? ? System.out.println("接收到一條新消息, 廣播給所有客戶端: " + msg);
? ? ? ? ? ? ? ? ? ? // 把消息對象msg傳給廣播方法(在下面定義的成員方法), 把消息輸出給所有的客戶端socket
? ? ? ? ? ? ? ? ? ? broadcastMessage(msg);
? ? ? ? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? ? ? break;// 出異常就break, 子線程退出
? ? ? ? ? ? ? ? } catch (ClassNotFoundException e) {
? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? // 廣播消息方法
? ? ? ? private void broadcastMessage(Message msg){
? ? ? ? ? ? // 遍歷socketList得到每一個客戶端的socket對象
? ? ? ? ? ? for (Socket sock : socketList) {
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? // 把socket底層的字節輸出流包裝成對象輸出流
? ? ? ? ? ? ? ? ? ? ObjectOutputStream oos = new ObjectOutputStream(sock.getOutputStream());
? ? ? ? ? ? ? ? ? ? // 把消息對象傳輸給客戶端
? ? ? ? ? ? ? ? ? ? oos.writeObject(msg);
? ? ? ? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? }
}
?
寫客戶端,新建項目
完成的結構
DateUtil和Message直接拷貝過來
寫客戶端Client類代碼
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Date;
import java.util.Scanner;
public class Client {
? ? static Scanner scanner = new Scanner(System.in);
? ? public static void main(String[] args) {
? ? ? ? Socket socket = null;// 客戶端socket
? ? ? ? try {
? ? ? ? ? ? // 初始化客戶端socket對象 - 三次握手, 建立socket連接
? ? ? ? ? ? socket = new Socket("192.168.25.100", 8081);// ip是服務端ip,端口同服務端
? ? ? ? ? ? System.out.println("登錄聊天室成功");
? ? ? ? ? ? // 開辟子線程發送消息, 把socket對象傳給子線程
? ? ? ? ? ? new SendMessageThread(socket).start();
? ? ? ? ? ? while (true){// 主線程中循環接收服務端推送過來的消息
? ? ? ? ? ? ? ? // 把socket底層的字節輸入流包裝成對象輸入流
? ? ? ? ? ? ? ? ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
? ? ? ? ? ? ? ? // 讀取服務端推送的消息對象, 如果服務端沒有返回, 此處會阻塞, 有返回就能立即讀到
? ? ? ? ? ? ? ? Message msg = (Message) ois.readObject();
? ? ? ? ? ? ? ? // 打印服務端推送的消息
? ? ? ? ? ? ? ? System.out.println("-------接收到一條新的消息--------");
? ? ? ? ? ? ? ? System.out.println(msg.getName() + "\t" + msg.getDate());
? ? ? ? ? ? ? ? System.out.println(msg.getMessage());
? ? ? ? ? ? ? ? System.out.println("");
? ? ? ? ? ? }
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? } catch (ClassNotFoundException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? }
? ? // 發送消息子線程靜態內部類, 繼承Thread類重寫run方法
? ? private static class SendMessageThread extends Thread{
? ? ? ? Socket socket;// 子線程socket成員變量
? ? ? ? // 子線程構造方法, 主線程通過參數中傳入socket
? ? ? ? public SendMessageThread(Socket socket) {
? ? ? ? ? ? this.socket = socket;
? ? ? ? }
? ? ? ? @Override
? ? ? ? public void run() {
? ? ? ? ? ? while (true){ // 循環接收用戶輸入, 并把輸入的內容封裝為消息對象發給服務端
? ? ? ? ? ? ? ? Message msg = new Message();
? ? ? ? ? ? ? ? System.out.println("回車發送:");
? ? ? ? ? ? ? ? msg.setMessage(scanner.next());
? ? ? ? ? ? ? ? msg.setName("葫蘆娃奇襲賽博坦");//用戶設置自己的昵稱,在代碼手動設置
? ? ? ? ? ? ? ? msg.setDate(DateUtil.date2String(new Date()));
? ? ? ? ? ? ? ? ObjectOutputStream oos = null;// 對象輸出流
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? // 把socket底層的字節輸c出流包裝成對象輸出流
? ? ? ? ? ? ? ? ? ? oos = new ObjectOutputStream(socket.getOutputStream());
? ? ? ? ? ? ? ? ? ? // 傳給消息對象msg給服務端
? ? ? ? ? ? ? ? ? ? oos.writeObject(msg);
? ? ? ? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? }
}
?
測試1:
先開啟服務端
再開啟客戶端接入服務端?
?我們在外面再開啟一個服務端接入虛擬機的客戶端
?發消息測試
win11虛擬機客戶端發消息
?外面電腦開啟客戶端發消息
?測試2
在自己電腦ipconfig查看自己的ip
?在自己電腦開啟服務端,開啟客戶端
?在虛擬機開啟客戶端連接
?沒有flush,有人退出的異常沒有拋出
總結
以上是生活随笔為你收集整理的【java IO流项目】实现多人实时聊天室,需连接同一WiFi的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 高光谱病虫害SPA x-Loading
- 下一篇: Oracle下载与安装