最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java實現(xiàn)在線聊天室(層層遞進(jìn))

 更新時間:2022年09月15日 10:56:41   作者:imByte  
這篇文章主要為大家詳細(xì)介紹了Java實現(xiàn)在線聊天室,層層遞進(jìn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下

本文實例為大家分享了Java實現(xiàn)在線聊天室的具體代碼,供大家參考,具體內(nèi)容如下

- 本文講述了從實現(xiàn)單個多個客戶的收發(fā)信息(基礎(chǔ)簡易版),到各種實現(xiàn)代碼的封裝(oop版),實現(xiàn)群聊(群聊過渡版),到最后實現(xiàn)私聊(終極版)的過程
- 本文內(nèi)容是在初步學(xué)習(xí)網(wǎng)絡(luò)編程時,練習(xí)強(qiáng)化記憶時的學(xué)習(xí)總結(jié)
- 主要利用了TCP網(wǎng)絡(luò)編程和多線程
- 如有問題,歡迎指出

綜合案例:在線聊天室

需求:使用TCP的Socket實現(xiàn)一個聊天室

  • 服務(wù)器端:一個線程專門發(fā)送消息,一個線程專門接收消息
  • 客戶端:一個線程專門發(fā)送消息,一個線程專門接收消息

1. 基礎(chǔ)簡易版

1.1 一個客戶收發(fā)多條消息

目標(biāo):實現(xiàn)一個客戶可以正常收發(fā)多條信息

服務(wù)器

/**
?* 在線聊天室: 服務(wù)器
?* 目標(biāo):實現(xiàn)一個客戶可以正常收發(fā)多條消息
?* ?服務(wù)器不生產(chǎn)內(nèi)容,相當(dāng)于一個轉(zhuǎn)發(fā)站,將客戶端的請求轉(zhuǎn)發(fā)
?*/
public class MutiChat {
? ? public static void main(String[] args) throws IOException {
? ? ? ? System.out.println("-----Server-----");
? ? ? ? // 1、指定端口 ?使用ServerSocket創(chuàng)建服務(wù)器
? ? ? ? ServerSocket server = new ServerSocket(8888);
? ? ? ? // 2、利用Socket的accept方法,監(jiān)聽客戶端的請求。阻塞,等待連接的建立
? ? ? ? Socket client = server.accept();
? ? ? ? System.out.println("一個客戶端建立了連接");
? ? ? ? DataInputStream dis = new DataInputStream(client.getInputStream());
? ? ? ? DataOutputStream dos = new DataOutputStream(client.getOutputStream());

? ? ? ? boolean isRunning = true;
? ? ? ? while (isRunning) {
? ? ? ? ? ? // 3、接收消息
? ? ? ? ? ? String msg = dis.readUTF();
? ? ? ? ? ? // 4、返回消息
? ? ? ? ? ? dos.writeUTF(msg);
? ? ? ? ? ? dos.flush();
? ? ? ? }
? ? ? ? // 5、釋放資源
? ? ? ? dos.close();
? ? ? ? dis.close();
? ? ? ? client.close();
? ? }
}

客戶端

/**
?* 在線聊天室: 客戶端
?* 目標(biāo):實現(xiàn)一個客戶可以正常收發(fā)(多條)信息
?*/
public class MutiClient {
? ? public static void main(String[] args) throws IOException {
? ? ? ? System.out.println("-----Client-----");
? ? ? ? // 1、建立連接:使用Socket創(chuàng)建客戶端 + 服務(wù)的地址和端口
? ? ? ? Socket client = new Socket("localhost", 8888);
? ? ? ? // 2、客戶端發(fā)送消息
? ? ? ? BufferedReader console = new BufferedReader(new InputStreamReader(System.in)); ?// 對接控制臺
? ? ? ? DataOutputStream dos = new DataOutputStream(client.getOutputStream());
? ? ? ? DataInputStream dis = new DataInputStream(client.getInputStream());

? ? ? ? boolean isRunning = true;
? ? ? ? while (isRunning) {
? ? ? ? ? ? String msg = console.readLine();
? ? ? ? ? ? dos.writeUTF(msg);
? ? ? ? ? ? dos.flush();
? ? ? ? ? ? // 3、獲取消息
? ? ? ? ? ? msg = dis.readUTF();
? ? ? ? ? ? System.out.println(msg);
? ? ? ? }

? ? ? ? // 4、釋放資源
? ? ? ? dos.close();
? ? ? ? dis.close();
? ? ? ? client.close();
? ? }
}

1.2 多個客戶收發(fā)多條消息(不使用多線程)

  • 目標(biāo):實現(xiàn)多個客戶可以正常收發(fā)多條信息
  • 出現(xiàn)排隊問題:其他客戶必須等待之前的客戶退出,才能收發(fā)消息

服務(wù)器

public class MutiChat {
? ? public static void main(String[] args) throws IOException {
? ? ? ? System.out.println("-----Server-----");
? ? ? ? // 1、指定端口 ?使用ServerSocket創(chuàng)建服務(wù)器
? ? ? ? ServerSocket server = new ServerSocket(8888);
? ? ? ? // 2、利用Socket的accept方法,監(jiān)聽客戶端的請求。阻塞,等待連接的建立
? ? ? ? while (true) {
? ? ? ? ? ? Socket client = server.accept();
? ? ? ? ? ? System.out.println("一個客戶端建立了連接");
? ? ? ? ? ? DataInputStream dis = new DataInputStream(client.getInputStream());
? ? ? ? ? ? DataOutputStream dos = new DataOutputStream(client.getOutputStream());

? ? ? ? ? ? boolean isRunning = true;
? ? ? ? ? ? while (isRunning) {
? ? ? ? ? ? ? ? // 3、接收消息
? ? ? ? ? ? ? ? String msg = dis.readUTF();
? ? ? ? ? ? ? ? // 4、返回消息
? ? ? ? ? ? ? ? dos.writeUTF(msg);
? ? ? ? ? ? ? ? dos.flush();
? ? ? ? ? ? }
? ? ? ? ? ? // 5、釋放資源
? ? ? ? ? ? dos.close();
? ? ? ? ? ? dis.close();
? ? ? ? ? ? client.close();
? ? ? ? }
? ? }
}

1.3 多個客戶收發(fā)多條消息(多線程)

  • 目標(biāo):實現(xiàn)多個客戶可以正常收發(fā)多條信息
  • 出現(xiàn)的問題:利用Lambda太復(fù)雜,代碼過多不好維護(hù);客戶端讀寫沒有分開,必須先寫后讀

服務(wù)器代碼

public class ThreadMutiChat {
? ? public static void main(String[] args) throws IOException {
? ? ? ? System.out.println("-----Server-----");
? ? ? ? // 1、指定端口 ?使用ServerSocket創(chuàng)建服務(wù)器
? ? ? ? ServerSocket server = new ServerSocket(8888);
? ? ? ? // 2、利用Socket的accept方法,監(jiān)聽客戶端的請求。阻塞,等待連接的建立
? ? ? ? while (true) {
? ? ? ? ? ? Socket client = server.accept();
? ? ? ? ? ? System.out.println("一個客戶端建立了連接");

? ? ? ? ? ? // 加入多線程
? ? ? ? ? ? new Thread(()->{
? ? ? ? ? ? ? ? DataInputStream dis = null;
? ? ? ? ? ? ? ? DataOutputStream dos = null;
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? dis = new DataInputStream(client.getInputStream());
? ? ? ? ? ? ? ? ? ? dos = new DataOutputStream(client.getOutputStream());
? ? ? ? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? boolean isRunning = true;
? ? ? ? ? ? ? ? while (isRunning) {
? ? ? ? ? ? ? ? ? ? // 3、接收消息
? ? ? ? ? ? ? ? ? ? String msg = null;
? ? ? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? ? ? msg = dis.readUTF();
? ? ? ? ? ? ? ? ? ? ? ? // 4、返回消息
? ? ? ? ? ? ? ? ? ? ? ? dos.writeUTF(msg);
? ? ? ? ? ? ? ? ? ? ? ? dos.flush();
? ? ? ? ? ? ? ? ? ? } catch (IOException e) {
// ? ? ? ? ? ? ? ? ? ? ? ?e.printStackTrace();
? ? ? ? ? ? ? ? ? ? ? ? isRunning = false; ?// 停止線程
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? // 5、釋放資源
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? if (null == dos) {
? ? ? ? ? ? ? ? ? ? ? ? dos.close();
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? if (null == dis) {
? ? ? ? ? ? ? ? ? ? ? ? dis.close();
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? if (null == client) {
? ? ? ? ? ? ? ? ? ? ? ? client.close();
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }).start();
? ? ? ? }
? ? }
}

2. oop封裝版

目標(biāo):封裝使用多線程實現(xiàn)多個客戶可以正常收發(fā)多條消息

  • 1、線程代理 Channel,一個客戶代表一個 Channel
  • 2、實現(xiàn)方法:接收消息 - receive; 發(fā)送消息 - send; 釋放資源 - release;
  • 3、其中釋放資源 release方法中利用工具類 Utils:實現(xiàn)Closeable接口、可變參數(shù)
  • 好處:利用封裝,是代碼簡潔,便于維護(hù)

服務(wù)器端

示例代碼:

public class ThreadMutiChat {
? ? public static void main(String[] args) throws IOException {
? ? ? ? System.out.println("---服務(wù)器開始工作---");
? ? ? ? // 1、指定端口 ?使用ServerSocket創(chuàng)建服務(wù)器
? ? ? ? ServerSocket server = new ServerSocket(8888);
? ? ? ? // 2、利用Socket的accept方法,監(jiān)聽客戶端的請求。阻塞,等待連接的建立
? ? ? ? while (true) {
? ? ? ? ? ? Socket client = server.accept();
? ? ? ? ? ? System.out.println("一個客戶端建立了連接");

? ? ? ? ? ? new Thread(new Channel(client)).start();
? ? ? ? }
? ? }

? ? // 一個客戶代表一個Channel
? ? static class Channel implements Runnable {
? ? ? ? private DataInputStream dis = null;
? ? ? ? private DataOutputStream dos = null;
? ? ? ? private Socket client;
? ? ? ? private boolean isRunning;

? ? ? ? public Channel(Socket client) {
? ? ? ? ? ? this.client = client;
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? dis = new DataInputStream(client.getInputStream());
? ? ? ? ? ? ? ? dos = new DataOutputStream(client.getOutputStream());
? ? ? ? ? ? ? ? isRunning = true;
? ? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ? System.out.println("---構(gòu)造時出現(xiàn)異常---");
? ? ? ? ? ? ? ? release();
? ? ? ? ? ? }
? ? ? ? }

? ? ? ? // 接收消息
? ? ? ? private String receive() {
? ? ? ? ? ? String msg = ""; ? ? ? ?// 避免空指針
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? msg = dis.readUTF();
? ? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ? System.out.println("---接受消息出現(xiàn)異常---");
? ? ? ? ? ? ? ? release();
? ? ? ? ? ? }
? ? ? ? ? ? return msg;
? ? ? ? }

? ? ? ? // 發(fā)送消息
? ? ? ? private void send(String msg) {
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? dos.writeUTF(msg);
? ? ? ? ? ? ? ? dos.flush();
? ? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ? System.out.println("---發(fā)送消息出現(xiàn)異常---");
? ? ? ? ? ? ? ? release();
? ? ? ? ? ? }
? ? ? ? }

? ? ? ? // 釋放資源
? ? ? ? private void release() {
? ? ? ? ? ? this.isRunning = false;
? ? ? ? ? ? // 封裝
? ? ? ? ? ? Utils.close(dis, dos, client);
? ? ? ? }

? ? ? ? // 線程體
? ? ? ? @Override
? ? ? ? public void run() {
? ? ? ? ? ? while (isRunning) {
? ? ? ? ? ? ? ? String msg = receive();
? ? ? ? ? ? ? ? if (!msg.equals("")) {
? ? ? ? ? ? ? ? ? ? send(msg);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? }
}

工具類Utils:實現(xiàn)Closeable接口,利用可變參數(shù),達(dá)到釋放資源的作用

示例代碼

public class Utils {
? ? public static void close(Closeable... targets) { ? ? ? ?
? ? // Closeable是IO流中接口,"..."可變參數(shù)
? ? // IO流和Socket都實現(xiàn)了Closeable接口,可以直接用
? ? ? ? for (Closeable target: targets) {
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? // 只要是釋放資源就要加入空判斷
? ? ? ? ? ? ? ? if (null != target) {
? ? ? ? ? ? ? ? ? ? target.close();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }catch (Exception e) {
?? ??? ??? ??? ?e.printStackTrace();
? ? ? ? ? ? }
? ? ? ? }
? ? }
}

客戶端:啟用兩個線程Send和Receive實現(xiàn)收發(fā)信息的分離

示例代碼

public class ThreadMutiClient {
? ? public static void main(String[] args) throws IOException {
? ? ? ? System.out.println("-----客戶端開始工作-----");
? ? ? ? Socket client = new Socket("localhost", 8888);

? ? ? ? new Thread(new Send(client)).start();
? ? ? ? new Thread(new Receive(client)).start();
? ? }
}

使用多線程封裝客戶的發(fā)送端 – Send類

實現(xiàn)方法:

1、發(fā)送消息 - send()
2、從控制臺獲取消息 - getStrFromConsole()
3、釋放資源 - release()
4、線程體 - run()

示例代碼

public class Send implements Runnable {
? ? private BufferedReader console;
? ? private DataOutputStream dos;
? ? private Socket client;
? ? private boolean isRunning;

? ? public Send(Socket client) {
? ? ? ? this.client = client;
? ? ? ? console = new BufferedReader(new InputStreamReader(System.in)); ?// 對接控制臺
? ? ? ? try {
? ? ? ? ? ? dos = new DataOutputStream(client.getOutputStream());
? ? ? ? ? ? isRunning = true;
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? System.out.println("---客戶發(fā)送端構(gòu)造時異常---");
? ? ? ? ? ? release();
? ? ? ? }
? ? }

? ? // 從控制臺獲取消息
? ? private String getStrFromConsole() {
? ? ? ? try {
? ? ? ? ? ? return console.readLine();
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? return "";
? ? ? ? }
? ? }

? ? // 發(fā)送消息
? ? private void send(String msg) {
? ? ? ? try {
? ? ? ? ? ? dos.writeUTF(msg);
? ? ? ? ? ? dos.flush();
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? System.out.println("---客戶發(fā)送端發(fā)送消息異常---");
? ? ? ? ? ? release();
? ? ? ? }
? ? }

? ? @Override
? ? public void run() {
? ? ? ? while (isRunning) {
? ? ? ? ? ? String msg = getStrFromConsole();
? ? ? ? ? ? if (!msg.equals("")) {
? ? ? ? ? ? ? ? send(msg);
? ? ? ? ? ? }
? ? ? ? }
? ? }

? ? // 釋放資源
? ? private void release() {
? ? ? ? this.isRunning = false;
? ? ? ? Utils.close(dos,client);
? ? }
}

使用多線程封裝客戶的接收端 – Receive類

實現(xiàn)方法:

1、接收消息 - send
2、釋放資源 - release()
3、線程體 - run()

示例代碼

public class Receive implements Runnable {
? ? private DataInputStream dis;
? ? private Socket client;
? ? private boolean isRunning;

? ? public Receive(Socket client) {
? ? ? ? this.client = client;
? ? ? ? try {
? ? ? ? ? ? dis = new DataInputStream(client.getInputStream());
? ? ? ? ? ? isRunning = true;
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? System.out.println("---客戶接收端構(gòu)造時異常---");
? ? ? ? ? ? release();
? ? ? ? }
? ? }

? ? // 接收消息
? ? private String receive() {
? ? ? ? String msg = "";
? ? ? ? try {
? ? ? ? ? ? msg = dis.readUTF();
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? System.out.println("---客戶接收端接收消息異常---");
? ? ? ? ? ? release();
? ? ? ? }
? ? ? ? return msg;
? ? }

? ? // 釋放資源
? ? private void release() {
? ? ? ? isRunning = false;
? ? ? ? Utils.close(dis, client);
? ? }

? ? @Override
? ? public void run() {
? ? ? ? while (isRunning) {
? ? ? ? ? ? String msg = receive();
? ? ? ? ? ? if (!msg.equals("")) {
? ? ? ? ? ? ? ? System.out.println(msg);
? ? ? ? ? ? }
? ? ? ? }
? ? }
}

3. 群聊過渡版

目標(biāo):加入容器,實現(xiàn)群聊

服務(wù)器端

1、建立 CopyOnWriteArrayList<Channel> 容器,容器中的元素是Channel客戶端代理。要對元素進(jìn)行修改同時遍歷時,推薦使用此容器,避免出問題。
2、實現(xiàn)方法void sendOthers(String msg)將信息發(fā)送給除自己外的其他人。

服務(wù)器端實現(xiàn)代碼

public class Chat {
? ? // 建立 CopyOnWriteArrayList<Channel> 容器
? ? private static CopyOnWriteArrayList<Channel> all = new CopyOnWriteArrayList<>();

? ? public static void main(String[] args) throws IOException {
? ? ? ? System.out.println("---服務(wù)器開始工作---");

? ? ? ? ServerSocket server = new ServerSocket(8888);

? ? ? ? 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("---構(gòu)造時出現(xiàn)問題---");
? ? ? ? ? ? ? ? release();
? ? ? ? ? ? }
? ? ? ? }

? ? ? ? // 接收消息
? ? ? ? private String receive() {
? ? ? ? ? ? String msg = ""; ? ? ? ?// 避免空指針
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? msg = dis.readUTF();
? ? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ? System.out.println("---接受消息出現(xiàn)問題---");
? ? ? ? ? ? ? ? release();
? ? ? ? ? ? }
? ? ? ? ? ? return msg;
? ? ? ? }

? ? ? ? // 發(fā)送消息
? ? ? ? private void send(String msg) {
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? dos.writeUTF(msg);
? ? ? ? ? ? ? ? dos.flush();
? ? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ? System.out.println("---發(fā)送消息出現(xiàn)問題---");
? ? ? ? ? ? ? ? release();
? ? ? ? ? ? }
? ? ? ? }

? ? ? ? // 群聊:把自己的消息發(fā)送給其他人
? ? ? ? private void sendOthers(String msg, boolean isSys) {
? ? ? ? ? ? for (Channel other : all) {
? ? ? ? ? ? ? ? if (other == this) {
? ? ? ? ? ? ? ? ? ? continue;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? if (!isSys) {
? ? ? ? ? ? ? ? ? ? other.send(this.name + ": " + msg); ?// 群聊消息
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? other.send("系統(tǒng)消息:" + msg); ? ?// 系統(tǒng)消息
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }

? ? ? ? // 線程體
? ? ? ? @Override
? ? ? ? public void run() {
? ? ? ? ? ? while (isRunning) {
? ? ? ? ? ? ? ? String msg = receive();
? ? ? ? ? ? ? ? if (!msg.equals("")) {
? ? ? ? ? ? ? ? ? ? sendOthers(msg, false);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }

? ? ? ? }

? ? ? ? // 釋放資源
? ? ? ? private void release() {
? ? ? ? ? ? this.isRunning = false;
? ? ? ? ? ? // 封裝
? ? ? ? ? ? Utils.close(dis, dos, client);
? ? ? ? ? ? // 退出
? ? ? ? ? ? all.remove(this);
? ? ? ? ? ? sendOthers(this.name + "離開聊天室", true);
? ? ? ? }
? ? }
}

客戶端實現(xiàn)代碼

public class Client {
? ? public static void main(String[] args) throws IOException {
? ? ? ? System.out.println("-----客戶端開始工作-----");
? ? ? ? BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
? ? ? ? Socket client = new Socket("localhost", 8888);
? ? ? ? System.out.println("請輸入用戶名:"); ? ? ?// 不考慮重名
? ? ? ? String name = br.readLine();


? ? ? ? new Thread(new Send(client, name)).start();
? ? ? ? new Thread(new Receive(client)).start();
? ? }
}

客戶端Send類實現(xiàn)代碼

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("Send類構(gòu)造時異常");
? ? ? ? ? ? release();
? ? ? ? }
? ? }

? ? // 從控制臺獲取消息
? ? private String getStrFromConsole() {
? ? ? ? try {
? ? ? ? ? ? return console.readLine();
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? return "";
? ? ? ? }
? ? }

? ? // 發(fā)送消息
? ? private void send(String msg) {
? ? ? ? try {
? ? ? ? ? ? dos.writeUTF(msg);
? ? ? ? ? ? dos.flush();
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? System.out.println("---客戶發(fā)送端發(fā)送消息異常---");
? ? ? ? ? ? release();
? ? ? ? }
? ? }

? ? @Override
? ? public void run() {
? ? ? ? while (isRunning) {
? ? ? ? ? ? String msg = getStrFromConsole();
? ? ? ? ? ? if (!msg.equals("")) {
? ? ? ? ? ? ? ? send(msg);
? ? ? ? ? ? }
? ? ? ? }
? ? }

? ? // 釋放資源
? ? private void release() {
? ? ? ? this.isRunning = false;
? ? ? ? Utils.close(dos,client);
? ? }
}

客戶端Receive類實現(xiàn)代碼

public class Receive implements Runnable {
? ? private DataInputStream dis;
? ? private Socket client;
? ? private boolean isRunning;

? ? public Receive(Socket client) {
? ? ? ? this.client = client;
? ? ? ? try {
? ? ? ? ? ? dis = new DataInputStream(client.getInputStream());
? ? ? ? ? ? isRunning = true;
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? System.out.println("---客戶接收端構(gòu)造時異常---");
? ? ? ? ? ? release();
? ? ? ? }
? ? }

? ? // 接收消息
? ? private String receive() {
? ? ? ? String msg = "";
? ? ? ? try {
? ? ? ? ? ? msg = dis.readUTF();
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? System.out.println("---客戶接收端接收消息異常---");
? ? ? ? ? ? release();
? ? ? ? }
? ? ? ? return msg;
? ? }

? ? // 釋放資源
? ? private void release() {
? ? ? ? isRunning = false;
? ? ? ? Utils.close(dis, client);
? ? }

? ? @Override
? ? public void run() {
? ? ? ? while (isRunning) {
? ? ? ? ? ? String msg = receive();
? ? ? ? ? ? if (!msg.equals("")) {
? ? ? ? ? ? ? ? System.out.println(msg);
? ? ? ? ? ? }
? ? ? ? }
? ? }
}

運(yùn)行結(jié)果

4. 終極版:實現(xiàn)私聊

私聊形式:@XXX:

實現(xiàn)方法

1、boolean isPrivate = msg.startsWith("@")用于判斷是否為私聊

  • 利用String類中方法
  • boolean startsWith(String prefix):測試此字符串是否以指定的前綴開頭

2、String targetName = msg.substring(1, index)用于判斷用戶名;msg = msg.substring(index+1)用于判斷發(fā)送的信息

  • 利用String類中方法
  • substring(int beginIndex):返回一個字符串,該字符串是此字符串的子字符串
  • substring(int beginIndex, int endIndex):返回一個字符串,該字符串是此字符串的子字符串

服務(wù)器端實現(xiàn)代碼

public class Chat {
? ? private static CopyOnWriteArrayList<Channel> all = new CopyOnWriteArrayList<>();

? ? public static void main(String[] args) throws IOException {
? ? ? ? System.out.println("---服務(wù)器開始工作---");

? ? ? ? ServerSocket server = new ServerSocket(8888);

? ? ? ? while (true) {
? ? ? ? ? ? Socket client = server.accept();
? ? ? ? ? ? System.out.println("一個客戶端建立了連接");
? ? ? ? ? ? Channel c = new Channel(client);
? ? ? ? ? ? all.add(c); ? ? // 管理所有的成員
? ? ? ? ? ? new Thread(c).start();
? ? ? ? }
? ? }
? ? 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("---構(gòu)造時出現(xiàn)問題---");
? ? ? ? ? ? ? ? release();
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? private String receive() {
? ? ? ? ? ? String msg = ""; ? ? ? ?// 避免空指針
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? msg = dis.readUTF();
? ? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ? System.out.println("---接受消息出現(xiàn)問題---");
? ? ? ? ? ? ? ? release();
? ? ? ? ? ? }
? ? ? ? ? ? return msg;
? ? ? ? }
? ? ? ? private void send(String msg) {
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? dos.writeUTF(msg);
? ? ? ? ? ? ? ? dos.flush();
? ? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ? System.out.println("---發(fā)送消息出現(xiàn)問題---");
? ? ? ? ? ? ? ? release();
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? /**
? ? ? ? ?* 群聊:把自己的消息發(fā)送給其他人
? ? ? ? ?* 私聊:約定數(shù)據(jù)格式:@XXX:msg
? ? ? ? ?* @param msg
? ? ? ? ?* @param isSys
? ? ? ? ?*/
? ? ? ? private void sendOthers(String msg, boolean isSys) {
? ? ? ? ? ? boolean isPrivate = msg.startsWith("@");
? ? ? ? ? ? if (isPrivate) { // 私聊
? ? ? ? ? ? ? ? int index = msg.indexOf(":"); ? ? ? // 第一次冒號出現(xiàn)的位置
? ? ? ? ? ? ? ? // 獲取目標(biāo)和數(shù)據(jù)
? ? ? ? ? ? ? ? String targetName = msg.substring(1, index);
? ? ? ? ? ? ? ? msg = msg.substring(index+1);
? ? ? ? ? ? ? ? for (Channel other: all) {
? ? ? ? ? ? ? ? ? ? if (other.name.equals(targetName)) { // 目標(biāo)
? ? ? ? ? ? ? ? ? ? ? ? other.send(this.name + "對您說悄悄話: " + msg); ?// 群聊消息
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? for (Channel other : all) {
? ? ? ? ? ? ? ? ? ? if (other == this) {
? ? ? ? ? ? ? ? ? ? ? ? continue;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? if (!isSys) {
? ? ? ? ? ? ? ? ? ? ? ? other.send(this.name + ": " + msg); ?// 群聊消息
? ? ? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? ? ? other.send("系統(tǒng)消息:" + msg); ? ?// 系統(tǒng)消息
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? @Override
? ? ? ? public void run() {
? ? ? ? ? ? while (isRunning) {
? ? ? ? ? ? ? ? String msg = receive();
? ? ? ? ? ? ? ? if (!msg.equals("")) {
? ? ? ? ? ? ? ? ? ? sendOthers(msg, false);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }

? ? ? ? }
? ? ? ? private void release() {
? ? ? ? ? ? this.isRunning = false;
? ? ? ? ? ? Utils.close(dis, dos, client);
? ? ? ? ? ? all.remove(this);
? ? ? ? ? ? sendOthers(this.name + "離開聊天室", true);
? ? ? ? }
? ? }
}

客戶端實現(xiàn)代碼

public class Client {
? ? public static void main(String[] args) throws IOException {
? ? ? ? System.out.println("-----客戶端開始工作-----");
? ? ? ? BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
? ? ? ? Socket client = new Socket("localhost", 8888);
? ? ? ? System.out.println("請輸入用戶名:"); ? ? ?// 不考慮重名
? ? ? ? String name = br.readLine();


? ? ? ? new Thread(new Send(client, name)).start();
? ? ? ? new Thread(new Receive(client)).start();
? ? }
}

客戶端Send類實現(xiàn)代碼

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("Send類構(gòu)造時異常");
? ? ? ? ? ? release();
? ? ? ? }
? ? }
? ? private String getStrFromConsole() {
? ? ? ? try {
? ? ? ? ? ? return console.readLine();
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? return "";
? ? ? ? }
? ? }
? ? private void send(String msg) {
? ? ? ? try {
? ? ? ? ? ? dos.writeUTF(msg);
? ? ? ? ? ? dos.flush();
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? System.out.println("---客戶發(fā)送端發(fā)送消息異常---");
? ? ? ? ? ? release();
? ? ? ? }
? ? }
? ? @Override
? ? public void run() {
? ? ? ? while (isRunning) {
? ? ? ? ? ? String msg = getStrFromConsole();
? ? ? ? ? ? if (!msg.equals("")) {
? ? ? ? ? ? ? ? send(msg);
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? private void release() {
? ? ? ? this.isRunning = false;
? ? ? ? Utils.close(dos,client);
? ? }
}

客戶端Receive類實現(xiàn)代碼

public class Receive implements Runnable {
? ? private DataInputStream dis;
? ? private Socket client;
? ? private boolean isRunning;

? ? public Receive(Socket client) {
? ? ? ? this.client = client;
? ? ? ? try {
? ? ? ? ? ? dis = new DataInputStream(client.getInputStream());
? ? ? ? ? ? isRunning = true;
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? System.out.println("---客戶接收端構(gòu)造時異常---");
? ? ? ? ? ? release();
? ? ? ? }
? ? }
? ??
? ? private String receive() {
? ? ? ? String msg = "";
? ? ? ? try {
? ? ? ? ? ? msg = dis.readUTF();
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? System.out.println("---客戶接收端接收消息異常---");
? ? ? ? ? ? release();
? ? ? ? }
? ? ? ? return msg;
? ? }
? ??
? ? private void release() {
? ? ? ? isRunning = false;
? ? ? ? Utils.close(dis, client);
? ? }
? ??
? ? @Override
? ? public void run() {
? ? ? ? while (isRunning) {
? ? ? ? ? ? String msg = receive();
? ? ? ? ? ? if (!msg.equals("")) {
? ? ? ? ? ? ? ? System.out.println(msg);
? ? ? ? ? ? }
? ? ? ? }
? ? }
}

Utils類實現(xiàn)代碼

public class Utils {
? ? public static void close(Closeable... targets) {
? ? ? ? for (Closeable target: targets) {
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? if (null != target) {
? ? ? ? ? ? ? ? ? ? target.close();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }catch (Exception e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? }
? ? ? ? }
? ? }
}

輸出結(jié)果

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java?SpringBoot?@Async實現(xiàn)異步任務(wù)的流程分析

    Java?SpringBoot?@Async實現(xiàn)異步任務(wù)的流程分析

    這篇文章主要介紹了Java?SpringBoot?@Async實現(xiàn)異步任務(wù),主要包括@Async?異步任務(wù)-無返回值,@Async?異步任務(wù)-有返回值,@Async?+?自定義線程池的操作代碼,需要的朋友可以參考下
    2022-12-12
  • Java設(shè)計模式之抽象工廠模式淺析講解

    Java設(shè)計模式之抽象工廠模式淺析講解

    當(dāng)系統(tǒng)所提供的工廠所需生產(chǎn)的具體產(chǎn)品并不是一個簡單的對象,而是多個位于不同產(chǎn)品等級結(jié)構(gòu)中屬于不同類型的具體產(chǎn)品時需要使用抽象工廠模式,抽象工廠模式是所有形式的工廠模式中最為抽象和最具一般性的一種形態(tài)
    2022-08-08
  • Java concurrency之公平鎖(二)_動力節(jié)點Java學(xué)院整理

    Java concurrency之公平鎖(二)_動力節(jié)點Java學(xué)院整理

    這篇文章主要為大家詳細(xì)介紹了Java concurrency之公平鎖的第二篇內(nèi)容,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • 基于springEL表達(dá)式詳解及應(yīng)用

    基于springEL表達(dá)式詳解及應(yīng)用

    這篇文章主要介紹了springEL表達(dá)式詳解及應(yīng)用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Java經(jīng)典面試題匯總:Spring MVC

    Java經(jīng)典面試題匯總:Spring MVC

    本篇總結(jié)的是Spring MVC框架相關(guān)的面試題,后續(xù)會持續(xù)更新,希望我的分享可以幫助到正在備戰(zhàn)面試的實習(xí)生或者已經(jīng)工作的同行,如果發(fā)現(xiàn)錯誤還望大家多多包涵,不吝賜教,謝謝
    2021-07-07
  • 消息隊列MQ使用詳解

    消息隊列MQ使用詳解

    消息隊列(MQ)是一種基于“先進(jìn)先出”原則的數(shù)據(jù)結(jié)構(gòu),廣泛應(yīng)用于分布式系統(tǒng)中,主要用于應(yīng)用解耦、異步消息處理和流量削峰,消息隊列中間件通過允許生產(chǎn)者發(fā)送消息到隊列,消費(fèi)者從隊列中拉取消息或訂閱消息,實現(xiàn)高效、可擴(kuò)展和最終一致性的系統(tǒng)架構(gòu)
    2024-10-10
  • Java實現(xiàn)操作JSON的便捷工具類完整實例【重寫Google的Gson】

    Java實現(xiàn)操作JSON的便捷工具類完整實例【重寫Google的Gson】

    這篇文章主要介紹了Java實現(xiàn)操作JSON的便捷工具類,基于重寫Google的Gson實現(xiàn),涉及java針對json數(shù)據(jù)的各種常見轉(zhuǎn)換操作實現(xiàn)技巧,需要的朋友可以參考下
    2017-10-10
  • java基于包結(jié)構(gòu)的請求路由實現(xiàn)實例分享

    java基于包結(jié)構(gòu)的請求路由實現(xiàn)實例分享

    基于包結(jié)構(gòu)的請求路由簡單實現(xiàn)實例分享,大家參考使用吧
    2013-12-12
  • 使用JPA傳遞參數(shù)的方法

    使用JPA傳遞參數(shù)的方法

    這篇文章主要介紹了使用JPA傳遞參數(shù)的方法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Java Swing中的表格(JTable)和樹(JTree)組件使用實例

    Java Swing中的表格(JTable)和樹(JTree)組件使用實例

    這篇文章主要介紹了Java Swing中的表格(JTable)和樹(JTree)組件使用實例,本文同時講解了表格和樹的基本概念、常用方法、代碼實例,需要的朋友可以參考下
    2014-10-10

最新評論

陇南市| 阳东县| 修武县| 五台县| 浦东新区| 灵宝市| 大冶市| 蓝山县| 旬阳县| 唐山市| 西青区| 双柏县| 阳山县| 偃师市| 德兴市| 万年县| 唐山市| 台中县| 海晏县| 灵宝市| 太康县| 肇东市| 武清区| 沙坪坝区| 仪征市| 吕梁市| 安龙县| 浙江省| 弥勒县| 四平市| 沙坪坝区| 赤峰市| 平南县| 宁安市| 兴海县| 西乌珠穆沁旗| 武隆县| 湾仔区| 克什克腾旗| 根河市| 浦东新区|