Java實現(xiàn)簡單的聊天室功能
本文實例為大家分享了Java實現(xiàn)簡單聊天室功能的具體代碼,供大家參考,具體內(nèi)容如下
一、客戶端的創(chuàng)建
1.我們可以用Socket來創(chuàng)建客戶端
/** ? *@類名 Client ? *@描述 TODO 客戶端 1 ? *@版本 1.0 ? *@創(chuàng)建人 XuKang ? *@創(chuàng)建時間 2020/9/24 16:18 ? **/ public class Client { ?? ?public static void main(String[] args) throws UnknownHostException, IOException { ?? ??? ?System.out.println("-----Client1-----"); ?? ??? ?BufferedReader br =new BufferedReader(new InputStreamReader(System.in)); ?? ??? ?System.out.println("請輸入用戶名:"); ?? ??? ?String name =br.readLine(); ?? ??? ?//1、建立連接: 使用Socket創(chuàng)建客戶端 +服務(wù)的地址和端口 ?? ??? ?Socket client =new Socket("localhost",8888); ?? ??? ?//2、客戶端發(fā)送消息 ?? ??? ?new Thread(new Send(client,name)).start(); ? ?? ??? ?new Thread(new Receive(client)).start(); ?? ?} }
2.這時我們需要接受其他客戶端發(fā)送的數(shù)據(jù),我們需要創(chuàng)建一個客戶端的接收方法和發(fā)送方法,我可以用阻塞式的方式進行接收和發(fā)送,考慮到多線程的安全性,可以實現(xiàn)Runnable
1.Send發(fā)送端:
/** ? *@類名 Send ? *@描述 TODO 使用多線程封裝:發(fā)送端 ? *@版本 1.0 ? *@創(chuàng)建人 XuKang ? *@創(chuàng)建時間 2020/9/24 16:23 ? **/ public class Send implements Runnable { ?? ?private BufferedReader console ; ?? ?private DataOutputStream dos; ?? ?private Socket client; ?? ?private boolean isRunning; ?? ?private String name; ?? ?public Send(Socket client,String name) { ?? ??? ?this.client =client; ?? ??? ?console =new BufferedReader(new InputStreamReader(System.in)); ?? ??? ?this.isRunning = true; ?? ??? ?this.name = name; ?? ??? ?try { ?? ??? ??? ?dos =new DataOutputStream(client.getOutputStream()); ?? ??? ??? ?//發(fā)送名稱 ?? ??? ??? ?send(name); ?? ??? ?} catch (IOException e) { ?? ??? ??? ?System.out.println("==1=="); ?? ??? ??? ?this.release(); ?? ??? ?}?? ? ?? ?} ?? ?@Override ?? ?public void run() { ?? ??? ?while(isRunning) { ?? ??? ??? ?String msg = getStrFromConsole(); ?? ??? ??? ?if(!msg.equals("")) { ?? ??? ??? ??? ?send(msg); ?? ??? ??? ?} ?? ??? ?} ?? ?}?? ? ?? ?//發(fā)送消息 ?? ?private void send(String msg) { ?? ??? ?try { ?? ??? ??? ?dos.writeUTF(msg); ?? ??? ??? ?dos.flush(); ?? ??? ?} catch (IOException e) { ?? ??? ??? ?System.out.println(e); ?? ??? ??? ?System.out.println("===3=="); ?? ??? ??? ?release(); ?? ??? ?} ?? ?} ?? ?/** ?? ? * 從控制臺獲取消息 ?? ? * @return ?? ? */ ?? ?private String getStrFromConsole() { ?? ??? ?try { ?? ??? ??? ?return ?console.readLine(); ?? ??? ?} catch (IOException e) { ?? ??? ??? ?e.printStackTrace(); ?? ??? ?} ?? ??? ?return ""; ?? ?} ?? ?//釋放資源 ?? ?private void release() { ?? ??? ?this.isRunning = false; ?? ??? ?CloseUtils.close(dos,client); ?? ?} }
2.接收端
/** ? *@類名 Receive ? *@描述 TODO 使用多線程封裝:接收端 ? *@版本 1.0 ? *@創(chuàng)建人 XuKang ? *@創(chuàng)建時間 2020/9/24 16:22 ? **/ public class Receive implements Runnable { ?? ?private DataInputStream dis ; ?? ?private Socket client; ?? ?private boolean isRunning; ?? ?public Receive(Socket client) { ?? ??? ?this.client = client; ?? ??? ?this.isRunning = true; ?? ??? ?try { ?? ??? ??? ?dis =new DataInputStream(client.getInputStream()); ?? ??? ?} catch (IOException e) { ?? ??? ??? ?System.out.println("====離開一位====="); ?? ??? ??? ?release(); ?? ??? ?} ?? ?} ?? ?//接收消息 ?? ?private String receive() { ?? ??? ?String msg =""; ?? ??? ?try { ?? ??? ??? ?msg =dis.readUTF(); ?? ??? ?} catch (IOException e) { ?? ??? ??? ?System.out.println("====接收消息異常===="); ?? ??? ??? ?release(); ?? ??? ?} ?? ??? ?return msg; ?? ?} ?? ? ?? ?@Override ?? ?public void run() {?? ??? ? ?? ??? ?while(isRunning) { ?? ??? ??? ?String msg =receive(); ?? ??? ??? ?if(!msg.equals("")) { ?? ??? ??? ??? ?System.out.println(msg); ?? ??? ??? ?} ?? ??? ?} ?? ?} ?? ?//釋放資源 ?? ?private void release() { ?? ??? ?this.isRunning = false; ?? ??? ?CloseUtils.close(dis,client); ?? ?} }
3.統(tǒng)一釋放資源的方法可以提出,服務(wù)的也用得上
/** ? *@類名 CloseUtils ? *@描述 TODO 工具類,統(tǒng)一釋放資源 ? *@版本 1.0 ? *@創(chuàng)建人 XuKang ? *@創(chuàng)建時間 2020/9/24 16:20 ? **/ public class CloseUtils { ?? ?/** ?? ? * 釋放資源 ?? ? */ ?? ?public static void close(Closeable... targets ) { ?? ??? ?for(Closeable target:targets) { ?? ??? ??? ?try { ?? ??? ??? ??? ?if(null!=target) { ?? ??? ??? ??? ??? ?target.close(); ?? ??? ??? ??? ?} ?? ??? ??? ?}catch(Exception e) { ?? ??? ??? ?} ?? ??? ?} ?? ?} }
二、客戶端的創(chuàng)建
服務(wù)端用ServerSocket創(chuàng)建,如果我們吧服務(wù)的和客戶端看成事一個通信通道(Channel),那么每個客戶端的接入都會創(chuàng)建一個通信通道,那么通信通道的創(chuàng)建也需要實現(xiàn)多線程,可以實現(xiàn)Runnable接口,我們存放通道可以用線程容器CopyOnWriteArrayList來存放通道。
/** ? *@類名 Chat ? *@描述 TODO Socket服務(wù)端(測試類) ? *@版本 1.0 ? *@創(chuàng)建人 XuKang ? *@創(chuàng)建時間 2020/9/24 16:17 ? **/ public class Chat { ?? ?private static CopyOnWriteArrayList<Channel> all =new CopyOnWriteArrayList<Channel>(); ?? ?public static void main(String[] args) throws IOException { ?? ??? ?System.out.println("-----Server-----"); ?? ??? ?// 1、指定端口 使用ServerSocket創(chuàng)建服務(wù)器 ?? ??? ?ServerSocket server =new ServerSocket(8888); ?? ??? ?// 2、阻塞式等待連接 accept ?? ??? ?while(true) { ?? ??? ??? ??? ?Socket ?client =server.accept();? ?? ??? ??? ??? ?System.out.println("一個客戶端建立了連接"); ?? ??? ??? ??? ?Channel c =new Channel(client); ?? ??? ??? ??? ?all.add(c); //管理所有的成員 ?? ??? ??? ??? ?new Thread(c).start();?? ??? ??? ? ?? ??? ??? ?}?? ??? ? ?? ??? ?} ?? ??? ?//一個客戶代表一個Channel ?? ??? ?static class Channel implements Runnable{ ?? ??? ??? ?private DataInputStream dis; ?? ??? ??? ?private DataOutputStream dos; ?? ??? ??? ?private Socket ?client;?? ??? ??? ? ?? ??? ??? ?private boolean isRunning; ?? ??? ??? ?private String name; ?? ??? ??? ?public Channel(Socket ?client) { ?? ??? ??? ??? ?this.client = client; ?? ??? ??? ??? ?try { ?? ??? ??? ??? ??? ?dis = new DataInputStream(client.getInputStream()); ?? ??? ??? ??? ??? ?dos =new DataOutputStream(client.getOutputStream()); ?? ??? ??? ??? ??? ?isRunning =true; ?? ??? ??? ??? ??? ?//獲取名稱 ?? ??? ??? ??? ??? ?this.name =receive();//退出出聊天室 ?? ??? ??? ??? ??? ?//歡迎你的到來 ?? ??? ??? ??? ??? ?this.send("歡迎你的到來"); ?? ??? ??? ??? ??? ?sendOthers(this.name+"來了徐康聊天室",true);//暫時固定為私聊 ?? ??? ??? ??? ?} catch (IOException e) { ?? ??? ??? ??? ??? ?System.out.println("---1------"); ?? ??? ??? ??? ??? ?release();?? ??? ??? ??? ??? ? ?? ??? ??? ??? ?}?? ??? ??? ? ?? ??? ??? ?} ?? ??? ??? ?//接收消息 ?? ??? ??? ?private String receive() { ?? ??? ??? ??? ?String msg =""; ?? ??? ??? ??? ?try { ?? ??? ??? ??? ??? ?msg =dis.readUTF(); ?? ??? ??? ??? ?} catch (IOException e) { ?? ??? ??? ??? ??? ?System.out.println("---2------"); ?? ??? ??? ??? ??? ?release(); ?? ??? ??? ??? ?} ?? ??? ??? ??? ?return msg; ?? ??? ??? ?} ?? ??? ??? ?//發(fā)送消息 ?? ??? ??? ?private void send(String msg) { ?? ??? ??? ??? ?try { ?? ??? ??? ??? ??? ?dos.writeUTF(msg); ?? ??? ??? ??? ??? ?dos.flush(); ?? ??? ??? ??? ?} catch (IOException e) { ?? ??? ??? ??? ??? ?System.out.println("---3------"); ?? ??? ??? ??? ??? ?release(); ?? ??? ??? ??? ?} ?? ??? ??? ?} ?? ??? ??? ?/** ?? ??? ??? ? * @方法名 sendOthers ?? ??? ??? ? * @描述 TODO 群聊:獲取自己的消息,發(fā)給其他人,需要設(shè)置isSys為false ?? ??? ??? ? * ?? ??? ? TODO 私聊: 約定數(shù)據(jù)格式: @xxx:msg ?? ??? ??? ? * @參數(shù) msg 發(fā)送內(nèi)容 ?? ??? ??? ? * @返回值 ?? ??? ??? ? * @創(chuàng)建人 XuKang ?? ??? ??? ? * @創(chuàng)建時間 2020/9/24 16:28 ?? ??? ??? ? */ ?? ??? ??? ?private void sendOthers(String msg,boolean isSys) { ?? ??? ??? ??? ?boolean isPrivate = msg.startsWith("@"); ?? ??? ??? ??? ?if(isPrivate) { //私聊 ?? ??? ??? ??? ??? ?int idx =msg.indexOf(":"); ?? ??? ??? ??? ??? ?//獲取目標和數(shù)據(jù) ?? ??? ??? ??? ??? ?String targetName = msg.substring(1,idx); ?? ??? ??? ??? ??? ?msg = msg.substring(idx+1); ?? ??? ??? ??? ??? ?for(Channel other: all) { ?? ??? ??? ??? ??? ??? ?if(other.name.equals(targetName)) {//目標 ?? ??? ??? ??? ??? ??? ??? ?other.send(this.name +"悄悄地對您說:"+msg); ?? ??? ??? ??? ??? ??? ??? ?break; ?? ??? ??? ??? ??? ??? ?} ?? ??? ??? ??? ??? ?} ?? ??? ??? ??? ?}else {?? ??? ??? ??? ? ?? ??? ??? ??? ??? ?for(Channel other: all) { ?? ??? ??? ??? ??? ??? ?if(other==this) { //自己 ?? ??? ??? ??? ??? ??? ??? ?continue; ?? ??? ??? ??? ??? ??? ?} ?? ??? ??? ??? ??? ??? ?if(!isSys) { ?? ??? ??? ??? ??? ??? ??? ?other.send(this.name +"對所有人說:"+msg);//群聊消息 ?? ??? ??? ??? ??? ??? ?}else { ?? ??? ??? ??? ??? ??? ??? ?other.send(msg); //系統(tǒng)消息 ?? ??? ??? ??? ??? ??? ?} ?? ??? ??? ??? ??? ?} ?? ??? ??? ??? ?} ?? ??? ??? ?} ?? ??? ??? ?//釋放資源 ?? ??? ??? ?private void release() { ?? ??? ??? ??? ?this.isRunning = false; ?? ??? ??? ??? ?CloseUtils.close(dis,dos,client); ?? ??? ??? ??? ?//退出 ?? ??? ??? ??? ?all.remove(this); ?? ??? ??? ??? ?sendOthers(this.name+"離開大家庭...",true); ?? ??? ??? ?} ?? ??? ??? ?@Override ?? ??? ??? ?public void run() { ?? ??? ??? ??? ?while(isRunning) { ?? ??? ??? ??? ??? ?String msg = receive() ; ?? ??? ??? ??? ??? ?if(!msg.equals("")) { ?? ??? ??? ??? ??? ??? ?//send(msg); ?? ??? ??? ??? ??? ??? ?sendOthers(msg,false); ?? ??? ??? ??? ??? ?} ?? ??? ??? ??? ?} ?? ??? ??? ?} ?? ??? ?} }
三、效果如下
1.啟動服務(wù)端
2.啟動客戶端
3.發(fā)送消息
總結(jié)
此案例只能用來打發(fā)時間,入門網(wǎng)絡(luò)編程可以參考一下,真正的開發(fā)不會這么弄。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 使用Java和WebSocket實現(xiàn)網(wǎng)頁聊天室實例代碼
- java聊天室的實現(xiàn)代碼
- java socket實現(xiàn)聊天室 java實現(xiàn)多人聊天功能
- Java基于socket實現(xiàn)簡易聊天室實例
- java實現(xiàn)一個簡單TCPSocket聊天室功能分享
- 基于java編寫局域網(wǎng)多人聊天室
- Java Socket聊天室編程(一)之利用socket實現(xiàn)聊天之消息推送
- Java基于UDP協(xié)議實現(xiàn)簡單的聊天室程序
- Java Socket聊天室編程(二)之利用socket實現(xiàn)單聊聊天室
- 使用java基于pushlet和bootstrap實現(xiàn)的簡單聊天室
相關(guān)文章
詳解SpringBoot項目的創(chuàng)建與單元測試
這篇文章主要介紹了詳解SpringBoot項目的創(chuàng)建與單元測試,幫助大家更好的理解和學(xué)習(xí)使用SpringBoot,感興趣的朋友可以了解下2021-03-03MyBatis批量插入大量數(shù)據(jù)(1w以上)
MyBatis進行批量插入數(shù)時,一次性插入超過一千條的時候MyBatis開始報錯,本文主要介紹了MyBatis批量插入大量數(shù)據(jù)的解決方法,感興趣的可以了解一下2022-01-01Java如何發(fā)起http請求的實現(xiàn)(GET/POST)
這篇文章主要介紹了Java如何發(fā)起http請求的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03SpringCloudAlibaba Nacos開啟鑒權(quán)解決跳過登錄頁面問題
對于Nacos,如果需要開啟權(quán)限控制,可以在 Nacos 控制臺上進行配置,本文主要介紹了SpringCloudAlibaba Nacos開啟鑒權(quán)解決跳過登錄頁面問題,感興趣的可以了解一下2023-10-10