Java實現(xiàn)局域網(wǎng)聊天小程序
本文實例為大家分享了Java實現(xiàn)局域網(wǎng)聊天的具體代碼,供大家參考,具體內容如下
開發(fā)環(huán)境:
IDEA 2018.2 集成開發(fā)工具。
實現(xiàn)功能:
1、用戶上線,向服務器通知并注冊。
2、同局域網(wǎng)下,所有注冊用戶可以進行群聊。
3、同局域網(wǎng)下,所有用戶可與任意已注冊用戶進行私聊。
4、用戶下線,通知服務器,服務器更新信息。
實現(xiàn)原理:
1、服務器端實例化一個ServerSocket對象,調用accept方法等待客戶端連接到服務器。
2、客戶端實例化 Socket 對象,并使用構造方法與服務器建立鏈接。
3、服務器端根據(jù)客戶端輸入信息,辨別客戶端請求的功能從而做出相應響應。
實用技術:
為了能夠高效的處理客戶端的請求,在服務器端使用多線程處理客戶端請求。并且使用 ConcurrentHashMap 來存儲所有注冊過的客戶端。
項目源碼(解釋寫在代碼的注釋當中):
服務器端:
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 { ? ? //存儲所有注冊的客戶端 ? ? private static Map<String, Socket> clientMap = new ConcurrentHashMap<String,Socket>(); ? ? //具體的處理每個客戶端的請求 ? ? 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要轉換為空字符串 ? ? ? ? ? ? ? ? ? ? ? ? Pattern pattern = Pattern.compile("\r"); ? ? ? ? ? ? ? ? ? ? ? ? Matcher matcher = pattern.matcher(strFromClient); ? ? ? ? ? ? ? ? ? ? ? ? strFromClient = matcher.replaceAll(""); ? ? ? ? ? ? ? ? ? ? ? ? //注冊流程 ? ? ? ? ? ? ? ? ? ? ? ? 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("當前共有用戶" + clientMap.size() + "人"); ? ? ? ? ? ? ? ? ? ? ? ? ? ? continue; ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? else{ ? ? ? ? ? ? ? ? ? ? ? ? ? ? PrintStream out = new PrintStream(client.getOutputStream(),true,"UTF-8"); ? ? ? ? ? ? ? ? ? ? ? ? ? ? out.println("輸入錯誤。。。"); ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } catch (IOException e) { ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? private void registerUser(String name,Socket client){ ? ? ? ? ? ? System.out.println("用戶:" + name + "已上線!"); ? ? ? ? ? ? clientMap.put(name,client); ? ? ? ? ? ? System.out.println("當前在線人數(shù):" + clientMap.size() + "人!"); ? ? ? ? ? ? //既然是用戶在注冊,所以這里服務器通知用戶注冊結果 ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? PrintStream out = new PrintStream(client.getOutputStream(),true,"UTF-8"); ? ? ? ? ? ? ? ? out.println("用戶注冊成功!"); ? ? ? ? ? ? } catch (IOException e) { ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? private void groupChat(String msg,Socket client){ ? ? ? ? ? ? //取出clientMap中所有的Entry對象,遍歷每個用戶,并且發(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("由端口號為"+ client.getPort() + "發(fā)來的群聊消息:" + 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("由端口號為:" + client.getPort() + "發(fā)來的消息:" + msg); ? ? ? ? ? ? } catch (IOException e) { ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? } ? ? ? ? } ? ? } ? ? public static void main(String[] args)throws Exception{ ? ? ? ? //為了提高效率,這里使用多線程進行處理 ? ? ? ? ExecutorService executorService = Executors.newFixedThreadPool(30); ? ? ? ? //實例化ServerSocket對象,并指定IP為本地主機,端口號為6666 ? ? ? ? ServerSocket serverSocket = new ServerSocket(6666); ? ? ? ? for(int i = 0; i < 30;i++){ ? ? ? ? ? ? System.out.println("等待用戶連接。。。"); ? ? ? ? ? ? //等待客戶端連接服務器 ? ? ? ? ? ? Socket client = serverSocket.accept(); ? ? ? ? ? ? System.out.println("有客戶端連接,端口號為:" + client.getPort()); ? ? ? ? ? ? //啟動線程,并處理客戶端請求 ? ? ? ? ? ? executorService.submit(new ExcuteClient(client)); ? ? ? ? } ? ? ? ? //關閉線程,關閉服務器 ? ? ? ? executorService.shutdown(); ? ? ? ? serverSocket.close(); ? ? } }
客戶端:
import java.io.IOException; import java.io.PrintStream; import java.net.Socket; import java.util.Scanner; ? /** ?* ?接收服務端發(fā)來的消息 ?*/ 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("服務器:" + in.nextLine()); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? //判斷客戶端是否退出,如果推出,跳出循環(huán),并關閉流 ? ? ? ? ? ? ? ? if (client.isClosed()) { ? ? ? ? ? ? ? ? ? ? System.out.println("客戶端關閉。。。"); ? ? ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? ? ? in.close(); ? ? ? ? } catch (IOException e) { ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? } ? ? } } ? /** ?* ?向服務端發(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("請輸入信息:"); ? ? ? ? ? ? ? ? String strToserver; ? ? ? ? ? ? ? ? if(scanner.hasNextLine()){ ? ? ? ? ? ? ? ? ? ? strToserver = scanner.nextLine().trim(); ? ? ? ? ? ? ? ? ? ? out.println(strToserver); ? ? ? ? ? ? ? ? ? ? //客戶端退出標志: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 { ? ? ? ? ? ? //實例化Socket對象,與服務器建立連接 ? ? ? ? ? ? Socket client = new Socket("127.0.0.1",6666); ? ? ? ? ? ? //為了發(fā)送消息和接收消息可以同時進行,使用多線程進行處理 ? ? ? ? ? ? Thread thread1 = new Thread(new FromServer(client)); ? ? ? ? ? ? Thread thread2 = new Thread(new ToServer(client)); ? ? ? ? ? ? thread1.start(); ? ? ? ? ? ? thread2.start(); ? ? ? ? } catch (IOException e) { ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? } ? ? } }
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
Spring security 如何開放 Swagger 訪問權限
這篇文章主要介紹了Spring security 如何開放 Swagger 訪問權限操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09JUC中的wait與notify方法實現(xiàn)原理詳解
這篇文章主要介紹了JUC中的wait與notify方法實現(xiàn)原理,在進行wait()之前,就代表著需要爭奪Synchorized,而Synchronized代碼塊通過javap生成的字節(jié)碼中包含monitor?enter和monitor?exit兩個指令2023-03-03Java使用Lambda表達式查找list集合中是否包含某值問題
Java使用Lambda表達式查找list集合中是否包含某值的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-06-06