亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

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

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

綜合案例:在線聊天室

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

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

1. 基礎(chǔ)簡易版

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

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

服務(wù)器

/**
?* 在線聊天室: 服務(wù)器
?* 目標(biāo):實(shí)現(xiàn)一個(gè)客戶可以正常收發(fā)多條消息
?* ?服務(wù)器不生產(chǎn)內(nèi)容,相當(dāng)于一個(gè)轉(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("一個(gè)客戶端建立了連接");
? ? ? ? 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):實(shí)現(xiàn)一個(gè)客戶可以正常收發(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 多個(gè)客戶收發(fā)多條消息(不使用多線程)

  • 目標(biāo):實(shí)現(xiàn)多個(gè)客戶可以正常收發(fā)多條信息
  • 出現(xiàn)排隊(duì)問題:其他客戶必須等待之前的客戶退出,才能收發(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("一個(gè)客戶端建立了連接");
? ? ? ? ? ? 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 多個(gè)客戶收發(fā)多條消息(多線程)

  • 目標(biāo):實(shí)現(xiàn)多個(gè)客戶可以正常收發(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("一個(gè)客戶端建立了連接");

? ? ? ? ? ? // 加入多線程
? ? ? ? ? ? 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):封裝使用多線程實(shí)現(xiàn)多個(gè)客戶可以正常收發(fā)多條消息

  • 1、線程代理 Channel,一個(gè)客戶代表一個(gè) Channel
  • 2、實(shí)現(xiàn)方法:接收消息 - receive; 發(fā)送消息 - send; 釋放資源 - release;
  • 3、其中釋放資源 release方法中利用工具類 Utils:實(shí)現(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("一個(gè)客戶端建立了連接");

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

? ? // 一個(gè)客戶代表一個(gè)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)造時(shí)出現(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:實(shí)現(xiàn)Closeable接口,利用可變參數(shù),達(dá)到釋放資源的作用

示例代碼

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

客戶端:啟用兩個(gè)線程Send和Receive實(shí)現(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類

實(shí)現(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)造時(shí)異常---");
? ? ? ? ? ? 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類

實(shí)現(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)造時(shí)異常---");
? ? ? ? ? ? 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):加入容器,實(shí)現(xiàn)群聊

服務(wù)器端

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

服務(wù)器端實(shí)現(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("一個(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();
? ? ? ? ? ? ? ? // 歡迎
? ? ? ? ? ? ? ? this.send("歡迎你的到來");
? ? ? ? ? ? ? ? sendOthers(this.name + "加入群聊", true);
? ? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ? System.out.println("---構(gòu)造時(shí)出現(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);
? ? ? ? }
? ? }
}

客戶端實(shí)現(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類實(shí)現(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)造時(shí)異常");
? ? ? ? ? ? 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類實(shí)現(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)造時(shí)異常---");
? ? ? ? ? ? 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. 終極版:實(shí)現(xiàn)私聊

私聊形式:@XXX:

實(shí)現(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):返回一個(gè)字符串,該字符串是此字符串的子字符串
  • substring(int beginIndex, int endIndex):返回一個(gè)字符串,該字符串是此字符串的子字符串

服務(wù)器端實(shí)現(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("一個(gè)客戶端建立了連接");
? ? ? ? ? ? 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)造時(shí)出現(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);
? ? ? ? }
? ? }
}

客戶端實(shí)現(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類實(shí)現(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)造時(shí)異常");
? ? ? ? ? ? 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類實(shí)現(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)造時(shí)異常---");
? ? ? ? ? ? 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類實(shí)現(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)文章

  • IDEA搭建dubbo項(xiàng)目的過程及存在的問題

    IDEA搭建dubbo項(xiàng)目的過程及存在的問題

    這篇文章主要介紹了IDEA搭建dubbo項(xiàng)目及存在的問題小結(jié),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-04-04
  • 淺談Java的LinkedHashSet源碼

    淺談Java的LinkedHashSet源碼

    這篇文章主要介紹了淺談Java的LinkedHashSet源碼,底層是鏈表實(shí)現(xiàn)的,是set集合中唯一一個(gè)能保證怎么存就怎么取的集合對象
    因?yàn)槭荋ashSet的子類,所以也是保證元素唯一的,與HashSet的原理一樣,需要的朋友可以參考下
    2023-09-09
  • Java中抓取 Thread Dumps 的方式匯總

    Java中抓取 Thread Dumps 的方式匯總

    Thread dumps(線程轉(zhuǎn)儲)能幫助我們判斷 CPU 峰值、死鎖、內(nèi)存異常、應(yīng)用反應(yīng)遲鈍、響應(yīng)時(shí)間變長和其他系統(tǒng)問題。在這篇文章當(dāng)中,總結(jié)了7中抓取 Java Thread Dumps 文件的方式,分享給大家,希望對大家學(xué)習(xí)Java能夠有所幫助。
    2016-06-06
  • JAVA實(shí)現(xiàn)redis分布式雙重加鎖的示例代碼

    JAVA實(shí)現(xiàn)redis分布式雙重加鎖的示例代碼

    在高并發(fā)環(huán)境下,通過Redis分布式鎖實(shí)現(xiàn)數(shù)據(jù)唯一性校驗(yàn)非常關(guān)鍵,為避免用戶數(shù)據(jù)重復(fù),可使用Redis鎖或集合數(shù)據(jù)結(jié)構(gòu)進(jìn)行前置檢查,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-10-10
  • IDEA2020 1.1中Plugins加載不出來的問題及解決方法

    IDEA2020 1.1中Plugins加載不出來的問題及解決方法

    這篇文章主要介紹了IDEA2020 1.1中Plugins加載不出來的問題,本文還給大家提到了IDEA 2020.1.1 找不到程序包和符號的問題,感興趣的朋友跟隨小編一起看看吧
    2020-06-06
  • Java實(shí)現(xiàn)JDK動態(tài)代理的原理詳解

    Java實(shí)現(xiàn)JDK動態(tài)代理的原理詳解

    這篇文章主要介紹了Java實(shí)現(xiàn)JDK動態(tài)代理的原理詳解,Java常用的動態(tài)代理模式有JDK動態(tài)代理,也有cglib動態(tài)代理,本文重點(diǎn)講解JDK的動態(tài)代理,需要的小伙伴可以參考一下的相關(guān)資料
    2022-07-07
  • Java設(shè)計(jì)模式常用的七大原則總結(jié)

    Java設(shè)計(jì)模式常用的七大原則總結(jié)

    今天給大家總結(jié)了Java設(shè)計(jì)模式的七大原則,主要有單一職責(zé)原則,接口隔離原則,依賴倒轉(zhuǎn)原則,里氏替換原則等,文中有非常詳細(xì)的介紹,需要的朋友可以參考下
    2021-06-06
  • Java使用lambda自定義Arrays.sort排序規(guī)則說明

    Java使用lambda自定義Arrays.sort排序規(guī)則說明

    這篇文章主要介紹了Java使用lambda自定義Arrays.sort排序規(guī)則說明,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-05-05
  • 手把手教你如何在Idea中下載jar包

    手把手教你如何在Idea中下載jar包

    maven依賴的jar包,很多時(shí)候同一個(gè)jar包會存在多個(gè)版本,刪除其中一個(gè)后,重新編譯,會把舊jar由加載回來了,下面這篇文章主要給大家介紹了關(guān)于如何在Idea中下載jar包的相關(guān)資料,需要的朋友可以參考下
    2023-06-06
  • JavaMail入門教程之創(chuàng)建郵件(2)

    JavaMail入門教程之創(chuàng)建郵件(2)

    這篇文章主要介紹了JavaMail入門教程之創(chuàng)建郵件的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-11-11

最新評論