Java聊天室----多線程實現羣聊、私聊、系統消息(有動圖演示呀呀呀)

是不是找了很多類似的博文都不能實現各個博主展示的效果呢?

原因在這我不談,但是我保證,你看了這篇文章,只要你動手,那肯定有收穫,沒收穫,那就是我蠢了

一、截圖效果展示

有效果纔有動力,這裏我就先展示效果

服務端截圖:
在這裏插入圖片描述

客戶端截圖:
在這裏插入圖片描述
羣聊與私聊截圖:
在這裏插入圖片描述

二、動圖演示

這裏我直接開了三個客戶端,不會開的可以留言哈
在這裏插入圖片描述

客戶端要定住它,不然它老是被切換,不會定的也可留言呀!!!

在這裏插入圖片描述

三、原理分析:(很重要呀呀)

  • 首先要知道客戶端與服務端的聯繫。

看我畫的圖:
在這裏插入圖片描述
說明分析:

1. 輸出流:OutputStream(發送數據)
2. 輸入流: InputStream(讀取數據)
3. 如果這個知識點你都不是很瞭解,那就去補補IO流知識哈

  1. 服務器端
  • 小夥伴們,這裏你別把服務器端想的太過於複雜高大尚
  • 這裏其實就是一個類,它主要是用來存儲數據、分發數據(我的理解)
  • 然後就是一個無限循環,等待相應客戶端,就這麼簡單哈
  • 多人聊天
  1. 多人聊天意味着服務端要響應多個客戶端,所以要在服務端開啓無限循環模式
  2. 因爲要多人聊天,所以就必須要加入多線程,不然就一直等待,直到某個客戶端退出
  3. 需要一個容器來管理客戶端,用它來進行各種操作(羣發消息、私聊,系統消息)
  • 羣聊結構圖
    在這裏插入圖片描述
    分析說明:
  1. 服務端通過receive方法(自己封裝),獲取數據
  2. 然後遍歷容器,分發給除掉自身的socket,調用其send()方法(也需要自行封裝)

四、擼代碼(核心)

光說不練歪把子

代碼都有詳細的解釋,我不信你看不懂,爲了代碼的可維護性,和整潔性,我將其進行了封裝(其實就是各自寫個函數、或者寫成一個類而已,沒有什麼大不了的哈)

工具類:

package socket_study03;

import java.io.Closeable;
import java.io.IOException;

/**
 * .工具類
 * 用途:用於關閉各種流操作,封裝一些代碼
 * @author 放牛娃學編程
 *
 */

public class Utils {
	
	//釋放資源(後邊帶...,它代表可變參數)
	public static void release(Closeable...targets)
	{
		for(Closeable target: targets)
		{
			try
			{
				if(null != target)
				{
					target.close();
				}
			}
			catch(IOException e)
			{
				e.printStackTrace();
			}
		}
	}
}

客戶端:

package socket_study03;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.Socket;


/**
 * 最終版:
 * 1.用多線程實現客戶端
 * 2.讀寫分開
 * 3.封裝代碼
 * 
 * 功能:羣聊、私聊
 * 
 * 私聊格式說明:@xxx:msg
 * 		
 * @author 放牛娃學編程(公衆號)
 *
 */

//發送(寫)線程類
class Send implements Runnable{
	private BufferedReader console;
	private DataOutputStream dos;
	private Socket client;
	private boolean flag;
	private String name;   //羣聊時的備註
	
	//構造器(用於數據初始化)
	public Send(Socket client, String name)
	{
		this.client = client;
		flag = true;
		this.name = name;
		console = new BufferedReader(new InputStreamReader(System.in));
		try {
			dos = new DataOutputStream(client.getOutputStream());
			
			//先將自己的備註發過去(服務端)
			send(name);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			this.release();
		}
	}
	
	//從控制檯獲取數據
	public String getFromConsole()
	{
		String msg = "";
		try {
			msg = console.readLine();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			release();
		}
		return msg;
	}
	
	//發送消息
	public void send(String msg)
	{
		if(!msg.equals(""))
		{
			try
			{
				dos.writeUTF(msg);
				dos.flush();
			}
			catch(IOException e)
			{
				e.printStackTrace();
			}

		}
	}
	
	//釋放資源
	public void release()
	{
		Utils.release(dos, client);
		this.flag = false;
	}

	//線程體
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(flag)
		{
			//獲取控制檯輸入的消息
			String msg = getFromConsole();
			
			//發送消息
			send(msg);
			
		}
		
	}
	
}

//接收(消息)線程類
class Receive implements Runnable{
	private DataInputStream dis;
	private boolean flag;
	private Socket client;
	
	//構造器,用於對數據的初始化
	public Receive(Socket client)
	{
		this.client = client;
		flag = true;
		try {
			dis = new DataInputStream(client.getInputStream());
		} catch (IOException e) {
			// TODO Auto-generated catch block
			this.release();
		}
	}
	
	//接收消息
	public void receive()
	{
		String msg = "";
		try {
			msg = dis.readUTF();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			release();
		}
		if(!msg.equals(""))
		{
			System.out.println(msg);
		}
	}
	
	//釋放資源
	//釋放資源
	public void release()
	{
		Utils.release(dis, client);
		this.flag = false;
	}

	//線程體
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(flag)
		{
			//接收消息
			receive();
		}
		
	}
	
}

public class Client {

	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		System.out.println("-------這是客戶端-----------");
		
		//獲取控制檯輸入流
		BufferedReader br = new BufferedReader(new java.io.InputStreamReader(System.in));
		System.out.println("進入羣聊前,請輸入你的備註");
		String name = br.readLine();
		
		//獲取socket管道
		Socket client = new Socket(InetAddress.getLocalHost(), 9898);
		
		//發送(寫)線程
		new Thread(new Send(client, name)).start();
		
		//接收(讀)線程
		new Thread(new Receive(client)).start();
		
	}
}

服務端:

限於篇幅這裏我只給出主線程的代碼(需要的自行提取)

	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		System.out.println("-----這是服務端----------");
		
		//獲取ServerSocket管道
		ServerSocket sSocket = new ServerSocket(9898);
		while(true)
		{
			//獲取客戶端的socket
			Socket client = sSocket.accept();
			System.out.println("一個客戶端連接成功");
			Channel channel = new Channel(client);
			
			//將每個客戶端添加到容器中,進行統一管理
			all.add(channel);
			
			//啓動線程
			new Thread(channel).start();
		}
	}
五、 各種bug吐槽方案
  1. 直接複製這裏的代碼在eclipse中運行是報錯的? 因爲服務端的代碼不全呀!!
  2. 如何獲取服務端代碼或者是整個項目? 關注公衆號後回覆:羣聊項目。或者加我微信我親自發你也行。
  3. 只需要服務端代碼,如何獲取? 點這就有了:Java聊天室----多線程實現羣聊、私聊、系統消息 (服務端完整代碼奉上)
  4. 小夥伴們,這個聊天項目測試通過,能夠完成既定目標(羣聊、私聊、系統回覆)

如果遇到問題,沒關係,多去折騰就完事了,也歡迎小夥伴們留言交流學習。

六、分享交流

最後有興趣一起交流的,可以關注我的公衆號:這裏你能夠學到很實用的技巧,不是常用的我不說,公衆號回覆提取碼即可獲取以下學習資料啦啦啦啦,喜歡就拿去吧!!

(鏈接時常會失效,若出現此類情況,可以加我微信:17722328325(加時請備註:學習資料))

  1. Java web從入門到精通電子書

  2. Python機器學習電子書

  3. Python400集(北京尚學堂)

  4. JavaScript項目案例、經典面試題

  5. Java300集(入門、精通)

  6. Java後端培訓機構錄集(同事培訓內部提供)

  7. IO流文檔

  8. JavaEE面試題及其參考答案文檔

  9. JavaSE面試題及其參考答案文檔

  10. java多線程技術文檔

  11. java網絡編程文檔

7~11都是之前同學花錢買來備戰找實習的,需要的我也分享出去了。

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章