Java實(shí)現(xiàn)局域網(wǎng)聊天小程序
本文實(shí)例為大家分享了Java實(shí)現(xiàn)局域網(wǎng)聊天的具體代碼,供大家參考,具體內(nèi)容如下
開(kāi)發(fā)環(huán)境:
IDEA 2018.2 集成開(kāi)發(fā)工具。
實(shí)現(xiàn)功能:
1、用戶上線,向服務(wù)器通知并注冊(cè)。
2、同局域網(wǎng)下,所有注冊(cè)用戶可以進(jìn)行群聊。
3、同局域網(wǎng)下,所有用戶可與任意已注冊(cè)用戶進(jìn)行私聊。
4、用戶下線,通知服務(wù)器,服務(wù)器更新信息。
實(shí)現(xiàn)原理:
1、服務(wù)器端實(shí)例化一個(gè)ServerSocket對(duì)象,調(diào)用accept方法等待客戶端連接到服務(wù)器。
2、客戶端實(shí)例化 Socket 對(duì)象,并使用構(gòu)造方法與服務(wù)器建立鏈接。
3、服務(wù)器端根據(jù)客戶端輸入信息,辨別客戶端請(qǐng)求的功能從而做出相應(yīng)響應(yīng)。
實(shí)用技術(shù):
為了能夠高效的處理客戶端的請(qǐng)求,在服務(wù)器端使用多線程處理客戶端請(qǐng)求。并且使用 ConcurrentHashMap 來(lái)存儲(chǔ)所有注冊(cè)過(guò)的客戶端。
項(xiàng)目源碼(解釋寫(xiě)在代碼的注釋當(dāng)中):
服務(wù)器端:
import java.io.IOException; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; import java.util.Map; import java.util.Scanner; import java.util.Set; import java.util.concurrent.*; import java.util.regex.Matcher; import java.util.regex.Pattern; public class ManyThreadServer { ? ? //存儲(chǔ)所有注冊(cè)的客戶端 ? ? private static Map<String, Socket> clientMap = new ConcurrentHashMap<String,Socket>(); ? ? //具體的處理每個(gè)客戶端的請(qǐng)求 ? ? private static class ExcuteClient implements Runnable{ ? ? ? ? private Socket client; ? ? ? ? public ExcuteClient(Socket client) { ? ? ? ? ? ? this.client = client; ? ? ? ? } ? ? ? ? @Override ? ? ? ? public void run() { ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? //獲取客戶端的輸出流,讀取客戶端消息,并處理 ? ? ? ? ? ? ? ? Scanner in = new Scanner(client.getInputStream()); ? ? ? ? ? ? ? ? String strFromClient; ? ? ? ? ? ? ? ? while(true){ ? ? ? ? ? ? ? ? ? ? if(in.hasNextLine()){ ? ? ? ? ? ? ? ? ? ? ? ? strFromClient = in.nextLine(); ? ? ? ? ? ? ? ? ? ? ? ? //在Windows下默認(rèn)換行是:\r\n,所以把\r要轉(zhuǎn)換為空字符串 ? ? ? ? ? ? ? ? ? ? ? ? Pattern pattern = Pattern.compile("\r"); ? ? ? ? ? ? ? ? ? ? ? ? Matcher matcher = pattern.matcher(strFromClient); ? ? ? ? ? ? ? ? ? ? ? ? strFromClient = matcher.replaceAll(""); ? ? ? ? ? ? ? ? ? ? ? ? //注冊(cè)流程 ? ? ? ? ? ? ? ? ? ? ? ? if(strFromClient.startsWith("useName")){ ? ? ? ? ? ? ? ? ? ? ? ? ? ? String useName = strFromClient.split("\\:")[1]; ? ? ? ? ? ? ? ? ? ? ? ? ? ? registerUser(useName,client); ? ? ? ? ? ? ? ? ? ? ? ? ? ? continue; ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? //群聊功能 ? ? ? ? ? ? ? ? ? ? ? ? if(strFromClient.startsWith("G")){ ? ? ? ? ? ? ? ? ? ? ? ? ? ? String msg = strFromClient.split("\\:")[1]; ? ? ? ? ? ? ? ? ? ? ? ? ? ? groupChat(msg,client); ? ? ? ? ? ? ? ? ? ? ? ? ? ? continue; ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? //私聊功能 ? ? ? ? ? ? ? ? ? ? ? ? if(strFromClient.startsWith("P")){ ? ? ? ? ? ? ? ? ? ? ? ? ? ? String userName = strFromClient.split("\\:")[1].split("-")[0]; ? ? ? ? ? ? ? ? ? ? ? ? ? ? String msg = strFromClient.split("\\:")[1].split("-")[1]; ? ? ? ? ? ? ? ? ? ? ? ? ? ? privateChat(userName,msg,client); ? ? ? ? ? ? ? ? ? ? ? ? ? ? continue; ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? //用戶退出 ? ? ? ? ? ? ? ? ? ? ? ? if(strFromClient.startsWith("B")){ ? ? ? ? ? ? ? ? ? ? ? ? ? ? String userName = null; ? ? ? ? ? ? ? ? ? ? ? ? ? ? //根據(jù)Socket找到UserName ? ? ? ? ? ? ? ? ? ? ? ? ? ? for(String keyName : clientMap.keySet()){ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if(clientMap.get(keyName).equals(client)){ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? userName = keyName; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? ? ? System.out.println("用戶" + userName + "下線了。。。"); ? ? ? ? ? ? ? ? ? ? ? ? ? ? clientMap.remove(userName); ? ? ? ? ? ? ? ? ? ? ? ? ? ? System.out.println("當(dāng)前共有用戶" + clientMap.size() + "人"); ? ? ? ? ? ? ? ? ? ? ? ? ? ? continue; ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? else{ ? ? ? ? ? ? ? ? ? ? ? ? ? ? PrintStream out = new PrintStream(client.getOutputStream(),true,"UTF-8"); ? ? ? ? ? ? ? ? ? ? ? ? ? ? out.println("輸入錯(cuò)誤。。。"); ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } catch (IOException e) { ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? private void registerUser(String name,Socket client){ ? ? ? ? ? ? System.out.println("用戶:" + name + "已上線!"); ? ? ? ? ? ? clientMap.put(name,client); ? ? ? ? ? ? System.out.println("當(dāng)前在線人數(shù):" + clientMap.size() + "人!"); ? ? ? ? ? ? //既然是用戶在注冊(cè),所以這里服務(wù)器通知用戶注冊(cè)結(jié)果 ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? PrintStream out = new PrintStream(client.getOutputStream(),true,"UTF-8"); ? ? ? ? ? ? ? ? out.println("用戶注冊(cè)成功!"); ? ? ? ? ? ? } catch (IOException e) { ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? private void groupChat(String msg,Socket client){ ? ? ? ? ? ? //取出clientMap中所有的Entry對(duì)象,遍歷每個(gè)用戶,并且發(fā)送消息 ? ? ? ? ? ? Set<Map.Entry<String,Socket>> clientSet = clientMap.entrySet(); ? ? ? ? ? ? for(Map.Entry<String,Socket> entry:clientSet){ ? ? ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? ? ? Socket socket = entry.getValue(); ? ? ? ? ? ? ? ? ? ? //取得輸出流,向客戶端發(fā)送消息 ? ? ? ? ? ? ? ? ? ? PrintStream out = new PrintStream(socket.getOutputStream(),true,"UTF-8"); ? ? ? ? ? ? ? ? ? ? out.println("由端口號(hào)為"+ client.getPort() + "發(fā)來(lái)的群聊消息:" + msg); ? ? ? ? ? ? ? ? } catch (IOException e) { ? ? ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? private void privateChat(String userName,String msg,Socket client){ ? ? ? ? ? ? Socket privateSocket = clientMap.get(userName); ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? PrintStream out = new PrintStream(privateSocket.getOutputStream(),true,"UTF-8"); ? ? ? ? ? ? ? ? out.println("由端口號(hào)為:" + client.getPort() + "發(fā)來(lái)的消息:" + msg); ? ? ? ? ? ? } catch (IOException e) { ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? } ? ? ? ? } ? ? } ? ? public static void main(String[] args)throws Exception{ ? ? ? ? //為了提高效率,這里使用多線程進(jìn)行處理 ? ? ? ? ExecutorService executorService = Executors.newFixedThreadPool(30); ? ? ? ? //實(shí)例化ServerSocket對(duì)象,并指定IP為本地主機(jī),端口號(hào)為6666 ? ? ? ? ServerSocket serverSocket = new ServerSocket(6666); ? ? ? ? for(int i = 0; i < 30;i++){ ? ? ? ? ? ? System.out.println("等待用戶連接。。。"); ? ? ? ? ? ? //等待客戶端連接服務(wù)器 ? ? ? ? ? ? Socket client = serverSocket.accept(); ? ? ? ? ? ? System.out.println("有客戶端連接,端口號(hào)為:" + client.getPort()); ? ? ? ? ? ? //啟動(dòng)線程,并處理客戶端請(qǐng)求 ? ? ? ? ? ? executorService.submit(new ExcuteClient(client)); ? ? ? ? } ? ? ? ? //關(guān)閉線程,關(guān)閉服務(wù)器 ? ? ? ? executorService.shutdown(); ? ? ? ? serverSocket.close(); ? ? } }
客戶端:
import java.io.IOException; import java.io.PrintStream; import java.net.Socket; import java.util.Scanner; ? /** ?* ?接收服務(wù)端發(fā)來(lái)的消息 ?*/ class FromServer implements Runnable{ ? ? Socket client; ? ? public FromServer(Socket client){ ? ? ? ? this.client = client; ? ? } ? ? @Override ? ? public void run() { ? ? ? ? try { ? ? ? ? ? ? Scanner in = new Scanner(client.getInputStream()); ? ? ? ? ? ? while (true) { ? ? ? ? ? ? ? ? if (in.hasNextLine()) { ? ? ? ? ? ? ? ? ? ? System.out.println("服務(wù)器:" + in.nextLine()); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? //判斷客戶端是否退出,如果推出,跳出循環(huán),并關(guān)閉流 ? ? ? ? ? ? ? ? if (client.isClosed()) { ? ? ? ? ? ? ? ? ? ? System.out.println("客戶端關(guān)閉。。。"); ? ? ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? ? ? in.close(); ? ? ? ? } catch (IOException e) { ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? } ? ? } } ? /** ?* ?向服務(wù)端發(fā)出消息 ?*/ class ToServer ?implements Runnable{ ? ? Socket client; ? ? public ToServer(Socket client){ ? ? ? ? this.client = client; ? ? } ? ? @Override ? ? public void run() { ? ? ? ? try { ? ? ? ? ? ? Scanner scanner = new Scanner(System.in); ? ? ? ? ? ? PrintStream out = new PrintStream(client.getOutputStream(),true,"UTF-8"); ? ? ? ? ? ? while (true) { ? ? ? ? ? ? ? ? System.out.println("請(qǐng)輸入信息:"); ? ? ? ? ? ? ? ? String strToserver; ? ? ? ? ? ? ? ? if(scanner.hasNextLine()){ ? ? ? ? ? ? ? ? ? ? strToserver = scanner.nextLine().trim(); ? ? ? ? ? ? ? ? ? ? out.println(strToserver); ? ? ? ? ? ? ? ? ? ? //客戶端退出標(biāo)志:B ? ? ? ? ? ? ? ? ? ? if(strToserver.startsWith("B")){ ? ? ? ? ? ? ? ? ? ? ? ? System.out.println("客戶端退出。。。"); ? ? ? ? ? ? ? ? ? ? ? ? scanner.close(); ? ? ? ? ? ? ? ? ? ? ? ? out.close(); ? ? ? ? ? ? ? ? ? ? ? ? client.close(); ? ? ? ? ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? } catch (IOException e) { ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? } ? ? } } public class ManyThreadClient { ? ? public static void main(String[] args){ ? ? ? ? try { ? ? ? ? ? ? //實(shí)例化Socket對(duì)象,與服務(wù)器建立連接 ? ? ? ? ? ? Socket client = new Socket("127.0.0.1",6666); ? ? ? ? ? ? //為了發(fā)送消息和接收消息可以同時(shí)進(jìn)行,使用多線程進(jìn)行處理 ? ? ? ? ? ? Thread thread1 = new Thread(new FromServer(client)); ? ? ? ? ? ? Thread thread2 = new Thread(new ToServer(client)); ? ? ? ? ? ? thread1.start(); ? ? ? ? ? ? thread2.start(); ? ? ? ? } catch (IOException e) { ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? } ? ? } }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Java實(shí)現(xiàn)局域網(wǎng)聊天室功能(私聊、群聊)
- Java用局域網(wǎng)實(shí)現(xiàn)聊天室功能
- java?socket實(shí)現(xiàn)局域網(wǎng)聊天
- Java創(chuàng)建多線程局域網(wǎng)聊天室實(shí)例
- Java實(shí)現(xiàn)簡(jiǎn)單局域網(wǎng)聊天室
- Java多線程局域網(wǎng)聊天室的實(shí)現(xiàn)
- java局域網(wǎng)聊天小程序
- java實(shí)現(xiàn)簡(jiǎn)易局域網(wǎng)聊天功能
- 基于java編寫(xiě)局域網(wǎng)多人聊天室
- java+socket實(shí)現(xiàn)簡(jiǎn)易局域網(wǎng)聊天室
相關(guān)文章
HashSet底層竟然是HashMap實(shí)現(xiàn)問(wèn)題
這篇文章主要介紹了HashSet底層竟然是HashMap實(shí)現(xiàn)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07Spring security 如何開(kāi)放 Swagger 訪問(wèn)權(quán)限
這篇文章主要介紹了Spring security 如何開(kāi)放 Swagger 訪問(wèn)權(quán)限操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09JUC中的wait與notify方法實(shí)現(xiàn)原理詳解
這篇文章主要介紹了JUC中的wait與notify方法實(shí)現(xiàn)原理,在進(jìn)行wait()之前,就代表著需要爭(zhēng)奪Synchorized,而Synchronized代碼塊通過(guò)javap生成的字節(jié)碼中包含monitor?enter和monitor?exit兩個(gè)指令2023-03-03POI通用導(dǎo)出Excel(.xls,.xlsx)的方法
這篇文章主要介紹了POI通用導(dǎo)出Excel(.xls,.xlsx)的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05Java的作業(yè)調(diào)度類庫(kù)Quartz基本使用指南
這篇文章主要介紹了Java的作業(yè)調(diào)度類庫(kù)Quartz基本使用指南,Quartz能夠讓類按照指定的計(jì)劃順序執(zhí)行,需要的朋友可以參考下2016-03-03Java使用Lambda表達(dá)式查找list集合中是否包含某值問(wèn)題
Java使用Lambda表達(dá)式查找list集合中是否包含某值的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06JPA多條件復(fù)雜SQL動(dòng)態(tài)分頁(yè)查詢功能
這篇文章主要介紹了JPA多條件復(fù)雜SQL動(dòng)態(tài)分頁(yè)查詢功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-09-09