国产成人精品久久免费动漫-国产成人精品天堂-国产成人精品区在线观看-国产成人精品日本-a级毛片无码免费真人-a级毛片毛片免费观看久潮喷

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

Java實(shí)現(xiàn)多線程聊天室

瀏覽:3日期:2022-08-09 17:49:16

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

用多線程來(lái)實(shí)現(xiàn),功能會(huì)比單線程聊天室更加齊全,也更人性化一點(diǎn)。

多線程版本的聊天室

1. 功能分析: 實(shí)現(xiàn)用戶注冊(cè),上線,下線 實(shí)現(xiàn)群聊和私聊 統(tǒng)計(jì)當(dāng)前在線人數(shù) 2. 服務(wù)端實(shí)現(xiàn)

1.維護(hù)所有的在線用戶

2.注冊(cè)功能:客戶端名稱(chēng),添加到服務(wù)器的客戶端集合里

3.群聊功能:客戶端發(fā)送消息,所有的客戶端都能接收到

4.私聊功能:客戶端與指定客戶端進(jìn)發(fā)送和接收消息

5.退出功能: 從服務(wù)器客戶端集合中移除客戶端

3. 客戶端實(shí)現(xiàn)

1.注冊(cè)功能:創(chuàng)建Socket對(duì)象,給服務(wù)器發(fā)送注冊(cè)執(zhí)行(消息)

2.群聊功能:客戶端發(fā)送和接收數(shù)據(jù)

3.私聊功能:客戶端指定客戶端(用戶),發(fā)送和接收數(shù)據(jù)

4.退出功能:給服務(wù)器發(fā)送退出指令(消息)

5.命令行的交互式輸入輸出

4.實(shí)現(xiàn)思路:

首先,要實(shí)現(xiàn)服務(wù)端與客戶端之間的連接

這里是使用套接字建立TCP連接:

(1)服務(wù)器端先實(shí)例化一個(gè)描述服務(wù)器端口號(hào)的ServerSocket對(duì)象

(2)客戶端要?jiǎng)?chuàng)建Socket對(duì)象來(lái)連接指定的服務(wù)器端

(3)服務(wù)器端調(diào)用ServerSocket類(lèi)的accept()方法來(lái)監(jiān)聽(tīng)連接到服務(wù)器端的客戶端信息

(4)若服務(wù)器端與客戶端連接成功,雙方將返回一個(gè)Socket對(duì)象,此時(shí)雙方可以進(jìn)行通信

(5)服務(wù)器端與客戶端使用I/O流進(jìn)行連接,服務(wù)端的輸出流連接客戶端的輸入流,客戶端的輸出流連接服務(wù)端的輸入流

(6)使用close()方法關(guān)閉套接字(一定要記得關(guān)閉)

2.因?yàn)槭菗碛幸粋€(gè)服務(wù)端來(lái)實(shí)現(xiàn)多個(gè)客戶端的連接,此處還要解決的是多線程的問(wèn)題。

每個(gè)客戶端需要兩個(gè)線程,來(lái)分別處理向服務(wù)端發(fā)送消息和向服務(wù)端接收消息

而服務(wù)端,當(dāng)每增加一個(gè)客戶端與服務(wù)端連接,服務(wù)端都要多創(chuàng)建一個(gè)線程來(lái)處理與客戶端的連接

5. 圖解析

Java實(shí)現(xiàn)多線程聊天室

6. 服務(wù)端代碼實(shí)現(xiàn)

Server類(lèi)

package test.Server; import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors; /** * package:test.Server * Description:服務(wù)器端 * @date:2019/8/14 * @Author:weiwei **/public class server { public static void main(String[] args) {try { int port = 6666; ServerSocket serverSocket = new ServerSocket(port); System.out.println('服務(wù)器啟動(dòng)...' + serverSocket.getLocalSocketAddress()); //服務(wù)器啟動(dòng),打印本地地址 //線程池 ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2); while (true) { //死循環(huán)Socket client = serverSocket.accept();System.out.println('有客戶端連接到服務(wù)器:' + client.getRemoteSocketAddress());executorService.execute(new HandlerClient(client)); }} catch (IOException e) { e.printStackTrace();} }}

HandlerClient類(lèi)

package test.Server; import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.io.OutputStreamWriter;import java.net.Socket;import java.util.Map;import java.util.Scanner;import java.util.concurrent.ConcurrentHashMap; /** * Author:weiwei * description:HandlerClient * Creat:2019/3/12 **/public class HandlerClient implements Runnable { /** * 維護(hù)所有的連接到服務(wù)端的客戶端對(duì)象 */ private static final Map<String,Socket> ONLINE_CLIENT_MAP = new ConcurrentHashMap<String, Socket>(); //靜態(tài)是為了不讓對(duì)象變化,final不讓對(duì)象被修改,ConcurrentHashMap是線程安全的類(lèi)//static final修飾后變量名應(yīng)該用常量--大寫(xiě)字母加下劃線分隔 private final Socket client; public HandlerClient(Socket client) { //HandlerClient在多線程環(huán)境下調(diào)用,所以會(huì)產(chǎn)生資源競(jìng)爭(zhēng),用一個(gè)并發(fā)的HashMapthis.client = client; //為了防止變量被修改,用final修飾 } //@Override public void run() {try { InputStream clientInput=client.getInputStream(); //獲取客戶端的數(shù)據(jù)流 Scanner scanner = new Scanner(clientInput); //字節(jié)流轉(zhuǎn)字符流 /** *消息是按行讀取 * 1.register:<username> 例如: register:張三 * 2.群聊: groupChat:<message> 例如:groupChat:大家好 * 3.私聊: privateChat:張三:你好,還錢(qián) * 4.退出:bye */ while(true){String data = scanner.nextLine(); //讀數(shù)據(jù),按行讀if(data.startsWith('register:')){ //注冊(cè) String userName = data.split(':')[1];//冒號(hào)分隔,取第一個(gè) register(userName); continue;} if(data.startsWith('groupChat:')){ String message = data.split(':')[1]; groupChat(message); continue;} if(data.startsWith('privateChat:')){ String [] segments = data.split(':'); String targetUserName = segments[1].split('-')[0]; //取目標(biāo)用戶名 String message = segments[1].split('-')[1]; //因?yàn)橐纱?所以用數(shù)組 //取發(fā)送的消息內(nèi)容 privateChat(targetUserName,message); continue;} if(data.equals('bye')){ //表示退出 bye(); continue;} }} catch (IOException e) { e.printStackTrace();} } /** * 當(dāng)前客戶端退出 */ private void bye() {for(Map.Entry<String,Socket> entry : ONLINE_CLIENT_MAP.entrySet()){ Socket target = entry.getValue(); if(target.equals(this.client)){ //在在線用戶中找到自己并且移除ONLINE_CLIENT_MAP.remove(entry.getKey());break; } System.out.println(getCurrentUserName()+'退出聊天室');}printOnlineClient();//打印當(dāng)前用戶 } private String getCurrentUserName(){for (Map.Entry<String, Socket> entry : ONLINE_CLIENT_MAP.entrySet()) { Socket target = entry.getValue(); //getvalue得到Socket對(duì)象 if(target.equals(this.client)){ //排除群聊的時(shí)候自己給自己發(fā)消息的情況return entry.getKey(); }}return ''; } /** * 私聊,給targetUserName發(fā)送message消息 * @param targetUserName * @param message */ private void privateChat(String targetUserName, String message) {Socket target = ONLINE_CLIENT_MAP.get(targetUserName);//獲取目標(biāo)用戶名if(target == null){ this.sendMessage(this.client,'沒(méi)有這個(gè)人'+targetUserName,false);}else{ this.sendMessage(target,message,true);} } /** * 群聊,發(fā)送message * @param message */ private void groupChat(String message) {for (Map.Entry<String, Socket> entery : ONLINE_CLIENT_MAP.entrySet()) { Socket target = entery.getValue(); //getvalue得到Socket對(duì)象 if(target.equals(this.client)){continue; //排除群聊的時(shí)候自己給自己發(fā)消息的情況 } this.sendMessage(target,message,true);} } /** * 以u(píng)serName為key注冊(cè)當(dāng)前用戶(Socket client) * @param userName */ private void register(String userName) {if(ONLINE_CLIENT_MAP.containsKey(userName)){ this.sendMessage(this.client,'您已經(jīng)注冊(cè)過(guò)了,無(wú)需重復(fù)注冊(cè)',false);}else{ ONLINE_CLIENT_MAP.put(userName,this.client); printOnlineClient(); this.sendMessage(this.client,'恭喜'+userName+'注冊(cè)成功n',false);} } private void sendMessage(Socket target,String message,boolean prefix){OutputStream clientOutput = null; //value是每一個(gè)客戶端try { clientOutput = target.getOutputStream(); OutputStreamWriter writer = new OutputStreamWriter(clientOutput); if(prefix) {String currentUserName = this.getCurrentUserName();writer.write('<' + currentUserName + '說(shuō):>' + message + 'n'); }else{writer.write( message + 'n'); } writer.flush();} catch (IOException e) { e.printStackTrace();} } /** * 打印在線客戶端 */ private void printOnlineClient(){System.out.println('當(dāng)前在線人數(shù):'+ONLINE_CLIENT_MAP.size()+','+'用戶名如下列表:');for(String userName : ONLINE_CLIENT_MAP.keySet()){ //Map的key為用戶名 System.out.println(userName);} }}7. 客戶端代碼實(shí)現(xiàn)

Client類(lèi)

package Cilent; import java.io.IOException;import java.net.Socket; /** * package:Cilent * Description:客戶端 * @date:2019/8/14 * @Author:weiwei **/public class cilent { public static void main(String[] args) {try { //讀取地址 String host = '127.0.0.1'; //讀取端口號(hào) int port = 6666; Socket client = new Socket(host,port); //先寫(xiě)數(shù)據(jù)再讀數(shù)據(jù),讀寫(xiě)線程分離 new ReadDataFromServerThread(client).start();//啟動(dòng)讀線程 new WriteDataToServerThread(client).start();//啟動(dòng)寫(xiě)線程} catch (IOException e) { e.printStackTrace();} }}

WriteDateToServer類(lèi)

package Cilent; import java.io.IOException;import java.io.OutputStream;import java.io.OutputStreamWriter;import java.net.Socket;import java.util.Scanner; /** * Author:weiwei * description:客戶端給服務(wù)端發(fā)送數(shù)據(jù)的線程 * 發(fā)送的數(shù)據(jù)來(lái)自命令行的交互式輸入 * Creat:2019/3/12 **/public class WriteDataToServerThread extends Thread{ private final Socket client; public WriteDataToServerThread(Socket client){this.client = client; } @Override public void run(){try { OutputStream clientOutput = this.client.getOutputStream(); OutputStreamWriter writer = new OutputStreamWriter(clientOutput); Scanner scanner = new Scanner(System.in); //有客戶端輸入數(shù)據(jù) while(true){System.out.print('請(qǐng)輸入>>');String data = scanner.nextLine(); //讀數(shù)據(jù)writer.write(data+'n');writer.flush();if(data.equals('bye')){ System.out.println('您已下線...'); break;} } this.client.close();} catch (IOException e) { // e.printStackTrace();} }}

ReadDateFromServer類(lèi)

package Cilent; import java.io.IOException;import java.io.InputStream;import java.net.Socket;import java.util.Scanner; /** * Author:weiwei * description:客戶端從服務(wù)端讀取數(shù)據(jù)的線程 * Creat:2019/3/12 **/public class ReadDataFromServerThread extends Thread { private final Socket client; public ReadDataFromServerThread(Socket client){this.client=client; } @Override public void run(){try { InputStream clientInput = this.client.getInputStream(); Scanner scanner = new Scanner(clientInput); while(true){String data = scanner.nextLine();//按行讀數(shù)據(jù)System.out.println('來(lái)自服務(wù)端消息:'+data); }} catch (IOException e) { e.printStackTrace();} }}

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持好吧啦網(wǎng)。

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 成人午夜毛片在线看 | 成人午夜兔费观看网站 | 久草在线国产视频 | 乱子伦农村xxxx | 亚洲国产日韩欧美 | 国产精品久久久久久久久久久威 | 欧美精品18videos性欧美 | 亚洲精品一区二区三区国产 | 欧美成人se01短视频在线看 | 亚洲黄色小视频 | 日本精品夜色视频一区二区 | 失禁h啪肉尿出来高h健身房 | 她也啪在线视频精品网站 | 久久久久综合国产 | 欧美成人观看免费完全 | 9丨精品国产高清自在线看 ⅹxx中国xxx人妖 | 日本三级网站在线线观看 | 亚洲欧美日韩在线播放 | 欧美激情第一欧美在线 | 亚洲欧美成人综合 | 亚洲综合图片人成综合网 | 69精品免费视频 | 欧美成人视屏 | 亚洲综合视频网 | 免费观看a视频 | 亚洲精品视频在线看 | 午夜影院h | 中文字幕亚洲 综合久久 | 国产精品免费看久久久 | 久久久久国产精品免费看 | 国产精品理论片在线观看 | 欧美激情国内自拍偷 | 毛片网站大全 | 成年美女黄网站色大 | 欧美性xxxx极品高清 | 亚洲夜 | 国产女人在线观看 | 加勒比综合 | 一区二区三区 日韩 | 国产精品午夜国产小视频 | 国产呦精品一区二区三区网站 |