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