java控制臺輸出版多人聊天室
本文實例為大家分享了java控制臺輸出版多人聊天室的具體代碼,供大家參考,具體內(nèi)容如下
多人聊天室就要用到網(wǎng)絡(luò)以及多線程以及輸入輸出流的知識
多人聊天室就是多個人同時聊天,一個發(fā)一條信息所有人都是可以接收得到.
接下來我們捋清楚一下思路
在這里面服務器充當了一個轉(zhuǎn)發(fā)的作用,服務器要做的事情是,得到客戶寫進緩沖流里面的信息,再把得到的信息再寫進其他客戶端的緩沖流里面,得到其他用戶的緩沖流我們可以通過集合把用戶的全部Socket對象寫進集合里面,客戶端把客戶想要發(fā)送的信息寫進緩沖流里,等待客戶端發(fā)來的消息,一邊等由一邊發(fā)送消息,這個是屬于并發(fā)的一個操作,所以讀與寫可以單獨開個線程來進行發(fā)送消息.
下面是客戶端的代碼
import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.List; public class Server { ? ? public static List<Socket> links = new ArrayList<>(); ?//用來存儲客戶端的socket對象 ? ? public static void main(String[] args) throws IOException { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ServerSocket serverSocket = new ServerSocket(6666); ? ? ? ? while(true){ ? ? ? ? ? ? Socket accept = serverSocket.accept(); ? ? ? ? ? ? links.add(accept); ? ? ? ? ? ? //只要有人連接就可以把他添加進socket對象集合里 ? ? ? ? ? ? ServerThread serverThread = new ServerThread(accept); ? ?//開啟多線程,實現(xiàn)多人聊天的功能 ? ? ? ? ? ? serverThread.start(); ? ? ? ? } } //因為頻繁的對輸入輸出流進行資源的關(guān)閉,所以寫了個關(guān)閉資源的工具類 import java.io.Closeable; import java.io.IOException; public class CloseUtil { ? ? public static void close(Closeable... closeables){ ? ? ? ? for (Closeable closeable : closeables) { ? ? ? ? ? ? if (closeable!=null) { ? ? ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? ? ? closeable.close(); ? ? ? ? ? ? ? ? } catch (IOException e) { ? ? ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? } ? ? } } //多線程的代碼如下 import java.io.*; import java.net.Socket; import java.util.List; public class ServerThread extends Thread { ? ? private Socket socket; ? ? private boolean flag = true; ? ? public ServerThread(String name, Socket socket) { ? ? ? ? super(name); ? ? ? ? this.socket = socket; ? ? } ? ? @Override ? ? public void run() { ? ? ? ? while(flag){ ? ? ? ? ? ? sendother(received()); ? ? //轉(zhuǎn)發(fā)功能 ? ? ? ? } ? ? } ? ? private void sendother(String str) ?{ ? ? ? ? List<Socket> links = Server.links; ? ? //因為在寫客戶端的時候是socket的集合是 靜態(tài)的屬性,所以可以直接通過類型.屬性直接獲得 ? ? ? ? for (Socket link : links) { ? ? ? ? ? ? if (link!=socket) ? ? ? ? ? ? ? ? ?send(str,link); ? ? ? ?//遍歷整個對象轉(zhuǎn)發(fā)給除當前對象的其他socket對象 ? ? ? ? } ? ? } ? ? private void send(String str,Socket socket) { ? ? ? ? BufferedWriter bw = null; ? ? ? ? try { ? ? ? ? ? ? OutputStream outputStream = socket.getOutputStream(); ? ? ? ? ? ? bw = new BufferedWriter(new OutputStreamWriter(outputStream)); ? ? ? ? ? ? bw.write(str); ? ? ? ? ? ? bw.newLine(); ? ? ? ? ? ? bw.flush(); ? ? ? ? } catch (IOException e) { ? ? ? ? ? ? flag = false; ? ? ? ? ? ? CloseUtil.close(bw,socket); ? ? ? ? } ? ? } ? ? private String received(){ ? ? ? ? BufferedReader br = null; ? ? ? ? try { ? ? ? ? ? ? InputStream inputStream = socket.getInputStream(); ? ? ? ? ? ? br = new BufferedReader(new InputStreamReader(inputStream)); ? ? ? ? ? ? return br.readLine(); ? ? ? ? } catch (IOException e) { ? ? ? ? ? ? flag = false; ? ? ? ? ? ? CloseUtil.close(br,socket); ? ? ? ? } ? ? ? ? return null; ? ? } }
下面是客戶端的代碼
import java.io.IOException; import java.net.Socket; import java.util.Scanner; public class Client { ? ? public static void main(String[] args) throws IOException { ? ? ? ? Scanner input ?= new Scanner(System.in); ? ? ? ? System.out.print("請輸入您的名字:"); ? ? ? ? String name = input.next(); ? ? ? ? Socket socket = new Socket("127.0.0.1", 6666); ?//127.0.0.1是指的是本機 ? ? ? ? Send send = new Send(socket,name); ? ? ? ? ?//收發(fā)分別開兩個線程,可以收發(fā)并發(fā)執(zhí)行 ? ? ? ? Receive receive = new Receive("",socket); ? ? ? ? send.start(); ? ? ? ? receive.start(); ? ? } } //發(fā)線程 import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.Socket; import java.util.Scanner; public class Send extends Thread { ? ? private Socket socket; ? ? private ?boolean flag = true; ? ? public Send(Socket socket,String name) { ? ? ? ? super(name); ? ? ? ? this.socket = socket; ? ? } ? ? @Override ? ? public void run() { ? ? ? ? while(flag){ ? ? ? ? ? ? send(); ? //一直循環(huán)保證客戶可以一直發(fā) ? ? ? ? } ? ? } ? ? private void send() { ? ? ? ? Scanner input = new Scanner(System.in); ? ? ? ? BufferedWriter bw= null; ? ? ? ? try { ? ? ? ? ? ? OutputStream outputStream = socket.getOutputStream(); ? ? ? ? ? ? bw = new BufferedWriter(new OutputStreamWriter(outputStream)); ? ? ? ? ? ? bw.write(this.getName()+"說:"+input.next()); ? ? ?// 當前線程名+在客戶端在控制臺輸出的一并發(fā)給服務端 ? ? ? ? ? ? bw.newLine(); ? ? ? ? ? ? bw.flush(); ? ? ? ? } catch (IOException e) { ? ? ? ? ? ? flag = false; ? ? ? ? //出現(xiàn)異常的時候關(guān)閉循環(huán),防止陷入死循環(huán) ? ? ? ? ? ? CloseUtil.close(bw,socket); ? ? ? ? } ? ? } } //收線程 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.Socket; public class Receive extends Thread { ? ? private Socket socket; ? ? private ?boolean flag = true; ? ? public Receive(String name, Socket socket) { ? ? ? ? super(name); ? ? ? ? this.socket = socket; ? ? } ? ? @Override ? ? public void run() { ? ? ? ? while (flag){ ? ? ? ? ? ? System.out.println(received()); ? ?//循環(huán)保證能一直接收服務器發(fā)來的消息 ? ? ? ? } ? ? } ? ? public String received(){ ? ? ? ? BufferedReader br =null; ? ? ? ? try { ? ? ? ? ? ? InputStream inputStream = socket.getInputStream(); ? ? ? ? ? ? br = new BufferedReader(new InputStreamReader(inputStream)); ? ? ? ? ? ? String line = br.readLine(); ? ? ? ? ? ? return this.getName()+line; ? ? ? ? } catch (IOException e) { ? ? ? ? ? ? flag = false; ? ? ? ? ? ? CloseUtil.close(br,socket); ? ? ? ? } ? ? ? ? return ""; ? ? } }
以上就是簡易版聊天室,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Java原生服務器接收上傳文件 不使用MultipartFile類
這篇文章主要為大家詳細介紹了Java原生服務器接收上傳文件,不使用MultipartFile類,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-09-09詳解Java中NullPointerException的處理方法
這篇文章將帶大家來單獨看一個很常見的異常--空指針異常,這個可以說是每個Java程序員都必知的異常,所以我們不得不單獨學習一下,文中有詳細的代碼示例,需要的朋友可以參考下2023-08-08Spring之兩種任務調(diào)度Scheduled和Async詳解
這篇文章主要介紹了Spring之兩種任務調(diào)度Scheduled和Async,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10MyBatis插入Insert、InsertSelective的區(qū)別及使用心得
這篇文章主要介紹了MyBatis插入Insert、InsertSelective的區(qū)別及使用心得,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12spring boot實現(xiàn)自動輸出word文檔功能的實例代碼
這篇文章主要介紹了spring boot實現(xiàn)自動輸出word文檔功能的實例代碼,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-04-04詳談Java中Object類中的方法以及finalize函數(shù)作用
下面小編就為大家?guī)硪黄斦凧ava中Object類中的方法以及finalize函數(shù)作用。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-04-04Java屬性文件操作之Properties與ResourceBundle詳解
這篇文章主要介紹了Java屬性文件操作之Properties與ResourceBundle詳解,兩個類都可以讀取屬性文件中以key/value形式存儲的鍵值對,ResourceBundle讀取屬性文件時操作相對簡單,需要的朋友可以參考下2023-11-11Mybatis中#{}和${}傳參的區(qū)別及#和$的區(qū)別小結(jié)
這篇文章主要介紹了Mybatis中#{}和${}傳參的區(qū)別及#和$的區(qū)別小結(jié) 的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-07-07