电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

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

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

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

用多線程來實現(xiàn),功能會比單線程聊天室更加齊全,也更人性化一點。

多線程版本的聊天室

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

1.維護所有的在線用戶

2.注冊功能:客戶端名稱,添加到服務器的客戶端集合里

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

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

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

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

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

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

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

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

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

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

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

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

(1)服務器端先實例化一個描述服務器端口號的ServerSocket對象

(2)客戶端要創(chuàng)建Socket對象來連接指定的服務器端

(3)服務器端調用ServerSocket類的accept()方法來監(jiān)聽連接到服務器端的客戶端信息

(4)若服務器端與客戶端連接成功,雙方將返回一個Socket對象,此時雙方可以進行通信

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

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

2.因為是擁有一個服務端來實現(xiàn)多個客戶端的連接,此處還要解決的是多線程的問題。

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

而服務端,當每增加一個客戶端與服務端連接,服務端都要多創(chuàng)建一個線程來處理與客戶端的連接

5. 圖解析

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

6. 服務端代碼實現(xiàn)

Server類

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:服務器端 * @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('服務器啟動...' + serverSocket.getLocalSocketAddress()); //服務器啟動,打印本地地址 //線程池 ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2); while (true) { //死循環(huán)Socket client = serverSocket.accept();System.out.println('有客戶端連接到服務器:' + client.getRemoteSocketAddress());executorService.execute(new HandlerClient(client)); }} catch (IOException e) { e.printStackTrace();} }}

HandlerClient類

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 { /** * 維護所有的連接到服務端的客戶端對象 */ private static final Map<String,Socket> ONLINE_CLIENT_MAP = new ConcurrentHashMap<String, Socket>(); //靜態(tài)是為了不讓對象變化,final不讓對象被修改,ConcurrentHashMap是線程安全的類//static final修飾后變量名應該用常量--大寫字母加下劃線分隔 private final Socket client; public HandlerClient(Socket client) { //HandlerClient在多線程環(huán)境下調用,所以會產(chǎn)生資源競爭,用一個并發(fā)的HashMapthis.client = client; //為了防止變量被修改,用final修飾 } //@Override public void run() {try { InputStream clientInput=client.getInputStream(); //獲取客戶端的數(shù)據(jù)流 Scanner scanner = new Scanner(clientInput); //字節(jié)流轉字符流 /** *消息是按行讀取 * 1.register:<username> 例如: register:張三 * 2.群聊: groupChat:<message> 例如:groupChat:大家好 * 3.私聊: privateChat:張三:你好,還錢 * 4.退出:bye */ while(true){String data = scanner.nextLine(); //讀數(shù)據(jù),按行讀if(data.startsWith('register:')){ //注冊 String userName = data.split(':')[1];//冒號分隔,取第一個 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]; //取目標用戶名 String message = segments[1].split('-')[1]; //因為要取兩次,所以用數(shù)組 //取發(fā)送的消息內容 privateChat(targetUserName,message); continue;} if(data.equals('bye')){ //表示退出 bye(); continue;} }} catch (IOException e) { e.printStackTrace();} } /** * 當前客戶端退出 */ 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();//打印當前用戶 } private String getCurrentUserName(){for (Map.Entry<String, Socket> entry : ONLINE_CLIENT_MAP.entrySet()) { Socket target = entry.getValue(); //getvalue得到Socket對象 if(target.equals(this.client)){ //排除群聊的時候自己給自己發(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);//獲取目標用戶名if(target == null){ this.sendMessage(this.client,'沒有這個人'+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對象 if(target.equals(this.client)){continue; //排除群聊的時候自己給自己發(fā)消息的情況 } this.sendMessage(target,message,true);} } /** * 以userName為key注冊當前用戶(Socket client) * @param userName */ private void register(String userName) {if(ONLINE_CLIENT_MAP.containsKey(userName)){ this.sendMessage(this.client,'您已經(jīng)注冊過了,無需重復注冊',false);}else{ ONLINE_CLIENT_MAP.put(userName,this.client); printOnlineClient(); this.sendMessage(this.client,'恭喜'+userName+'注冊成功n',false);} } private void sendMessage(Socket target,String message,boolean prefix){OutputStream clientOutput = null; //value是每一個客戶端try { clientOutput = target.getOutputStream(); OutputStreamWriter writer = new OutputStreamWriter(clientOutput); if(prefix) {String currentUserName = this.getCurrentUserName();writer.write('<' + currentUserName + '說:>' + message + 'n'); }else{writer.write( message + 'n'); } writer.flush();} catch (IOException e) { e.printStackTrace();} } /** * 打印在線客戶端 */ private void printOnlineClient(){System.out.println('當前在線人數(shù):'+ONLINE_CLIENT_MAP.size()+','+'用戶名如下列表:');for(String userName : ONLINE_CLIENT_MAP.keySet()){ //Map的key為用戶名 System.out.println(userName);} }}7. 客戶端代碼實現(xiàn)

Client類

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'; //讀取端口號 int port = 6666; Socket client = new Socket(host,port); //先寫數(shù)據(jù)再讀數(shù)據(jù),讀寫線程分離 new ReadDataFromServerThread(client).start();//啟動讀線程 new WriteDataToServerThread(client).start();//啟動寫線程} catch (IOException e) { e.printStackTrace();} }}

WriteDateToServer類

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:客戶端給服務端發(fā)送數(shù)據(jù)的線程 * 發(fā)送的數(shù)據(jù)來自命令行的交互式輸入 * 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('請輸入>>');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類

package Cilent; import java.io.IOException;import java.io.InputStream;import java.net.Socket;import java.util.Scanner; /** * Author:weiwei * description:客戶端從服務端讀取數(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('來自服務端消息:'+data); }} catch (IOException e) { e.printStackTrace();} }}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持好吧啦網(wǎng)。

標簽: Java
相關文章:
主站蜘蛛池模板: 光伏家 - 太阳能光伏发电_分布式光伏发电_太阳能光伏网 | 轴承振动测量仪电箱-轴承测振动仪器-测试仪厂家-杭州居易电气 | 滁州高低温冲击试验箱厂家_安徽高低温试验箱价格|安徽希尔伯特 | 液压压力机,液压折弯机,液压剪板机,模锻液压机-鲁南新力机床有限公司 | 自动化生产线-自动化装配线-直流电机自动化生产线-东莞市慧百自动化有限公司 | 深圳市宏康仪器科技有限公司-模拟高空低压试验箱-高温防爆试验箱-温控短路试验箱【官网】 | 河北中仪伟创试验仪器有限公司是专业生产沥青,土工,水泥,混凝土等试验仪器的厂家,咨询电话:13373070969 | 萃取箱-萃取槽-PVC萃取箱厂家-混合澄清槽- 杭州南方化工设备 | 玖容气动液压设备有限公司-气液增压缸_压力机_增压机_铆接机_增压器 | 陕西自考报名_陕西自学考试网 | 酒万铺-酒水招商-酒水代理 | 上海律师咨询_上海法律在线咨询免费_找对口律师上策法网-策法网 广东高华家具-公寓床|学生宿舍双层铁床厂家【质保十年】 | 富森高压水枪-柴油驱动-养殖场高压清洗机-山东龙腾环保科技有限公司 | 12cr1mov无缝钢管切割-15crmog无缝钢管切割-40cr无缝钢管切割-42crmo无缝钢管切割-Q345B无缝钢管切割-45#无缝钢管切割 - 聊城宽达钢管有限公司 | 紫外线老化试验箱_uv紫外线老化试验箱价格|型号|厂家-正航仪器设备 | 招商帮-一站式网络营销服务|搜索营销推广|信息流推广|短视视频营销推广|互联网整合营销|网络推广代运营|招商帮企业招商好帮手 | 凝胶成像仪,化学发光凝胶成像系统,凝胶成像分析系统-上海培清科技有限公司 | 注浆压力变送器-高温熔体传感器-矿用压力传感器|ZHYQ朝辉 | 纸塑分离机-纸塑分离清洗机设备-压力筛-碎浆机厂家金双联环保 | 齿式联轴器-弹性联轴器-联轴器厂家-江苏诺兴传动联轴器制造有限公司 | 纯水电导率测定仪-万用气体检测仪-低钠测定仪-米沃奇科技(北京)有限公司www.milwaukeeinst.cn 锂辉石检测仪器,水泥成分快速分析仪-湘潭宇科分析仪器有限公司 手术室净化装修-手术室净化工程公司-华锐手术室净化厂家 | 无线遥控更衣吊篮_IC卡更衣吊篮_电动更衣吊篮配件_煤矿更衣吊篮-力得电子 | 北京三友信电子科技有限公司-ETC高速自动栏杆机|ETC机柜|激光车辆轮廓测量仪|嵌入式车道控制器 | 环球电气之家-中国专业电气电子产品行业服务网站! | 德国进口电锅炉_商用电热水器_壁挂炉_电采暖器_电热锅炉[德国宝] | 深圳律师咨询_深圳律师事务所_华荣【免费在线法律咨询】网 | 锂电混合机-新能源混合机-正极材料混料机-高镍,三元材料混料机-负极,包覆混合机-贝尔专业混合混料搅拌机械系统设备厂家 | 高清视频编码器,4K音视频编解码器,直播编码器,流媒体服务器,深圳海威视讯技术有限公司 | 上海小程序开发-上海小程序制作公司-上海网站建设-公众号开发运营-软件外包公司-咏熠科技 | 高效复合碳源-多核碳源生产厂家-污水处理反硝化菌种一长隆科技库巴鲁 | 无菌实验室规划装修设计-一体化实验室承包-北京洁净净化工程建设施工-北京航天科恩实验室装备工程技术有限公司 | 雄松华章(广州华章MBA)官网-专注MBA/MPA/MPAcc/MEM辅导培训 | 软启动器-上海能曼电气有限公司 真空搅拌机-行星搅拌机-双行星动力混合机-广州市番禺区源创化工设备厂 | HEYL硬度计量泵-荧光法在线溶解氧仪-净时测控技术(上海)有限公司 | 成都装修公司-成都装修设计公司推荐-成都朗煜装饰公司 | 江苏南京多语种翻译-专业翻译公司报价-正规商务翻译机构-南京华彦翻译服务有限公司 | 可程式恒温恒湿试验箱|恒温恒湿箱|恒温恒湿试验箱|恒温恒湿老化试验箱|高低温试验箱价格报价-广东德瑞检测设备有限公司 | 水稻烘干机,小麦烘干机,大豆烘干机,玉米烘干机,粮食烘干机_巩义市锦华粮食烘干机械制造有限公司 水环真空泵厂家,2bv真空泵,2be真空泵-淄博真空设备厂 | 盘煤仪,盘料仪,盘点仪,堆料测量仪,便携式激光盘煤仪-中科航宇(北京)自动化工程技术有限公司 | 新能源汽车电池软连接,铜铝复合膜柔性连接,电力母排-容发智能科技(无锡)有限公司 | 干洗加盟网-洗衣店品牌排行-干洗设备价格-干洗连锁加盟指南 |