Java 实现局域网聊天室功能(私聊,群聊)
生活随笔
收集整理的這篇文章主要介紹了
Java 实现局域网聊天室功能(私聊,群聊)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Server 服務端
import java.io.IOException; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket;/*** 服務端*/ public class Server {private static final int SERVER_PORT=8080;//使用CrazyitMap對象來保存每個客戶名字和對應輸出流之間的對應關系public static CrazyitMap<String,PrintStream> clients=new CrazyitMap<>();public void init(){try( //建立監聽的ServerSocketServerSocket ss=new ServerSocket(SERVER_PORT)){//采用死循環來不斷地接收來自客戶端的請求while(true){Socket socket=ss.accept();new ServerThread(socket).start();}}//如果拋出異常catch (IOException ex){System.out.println("服務器啟動失敗,是否端口"+SERVER_PORT+"已被占用");}}public static void main(String[] args){Server server=new Server();server.init();} }ServerThread 服務端線程
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.Socket;/*** 服務端線程*/ public class ServerThread extends Thread {private Socket socket;BufferedReader br = null;PrintStream ps = null;//定義一個構造器,用于接收一個Socket來創建ServerThread線程public ServerThread(Socket socket) {this.socket = socket;}public void run() {try {//獲取該Socket對應的輸入流br = new BufferedReader(new InputStreamReader(socket.getInputStream()));//獲取該Socket對應的輸出流ps = new PrintStream(socket.getOutputStream());String line = null;while ((line = br.readLine()) != null) {//如果讀到的行以CrazyitProtocol.USER_ROUND開始,并以其結束//則可以確定讀到的是用戶登錄的用戶名if (line.startsWith(CrazyitProtocol.USER_ROUND) && line.endsWith(CrazyitProtocol.USER_ROUND)) {//得到真實消息String userName = getRealMsg(line);//如果用戶名重復if (Server.clients.map.containsKey(userName)) {System.out.println("重復");ps.println(CrazyitProtocol.NAME_REP);} else {System.out.println(userName+"上線");ps.println(CrazyitProtocol.LOGIN_SUCCESS);Server.clients.put(userName, ps);}}//如果讀到的行以CrazyitProtocol.PRIVATE_ROUND開始,//則可以確定是私聊信息,私聊信息只向特定的輸入流發送else if (line.startsWith(CrazyitProtocol.PRIVATE_ROUND) && line.endsWith(CrazyitProtocol.PRIVATE_ROUND)) {//得到真實的消息String userAndMsg = getRealMsg(line);//以SPLIT_SIGN分割字符串,前半是私聊用戶,后半是聊天信息String user = userAndMsg.split(CrazyitProtocol.SPLIT_SIGN)[0];String msg = userAndMsg.split(CrazyitProtocol.SPLIT_SIGN)[1];//獲取私聊用戶對應的輸出流,并發送私聊信息Server.clients.map.get(user).println(Server.clients.getKeyByValue(ps) + "悄悄對你說:" + msg);}//公聊要向每一個Socket發送else {//得到真實消息String msg = getRealMsg(line);//遍歷clients中的每個輸出流for (PrintStream clientPs : Server.clients.valueSet()) {clientPs.println(Server.clients.getKeyByValue(ps) + "說:" + msg);}}}}//捕獲到異常后,表明Socket對應的客戶端已經出現了問題//所以程序將其對應的輸出流從Map中刪除catch (IOException e) {Server.clients.removeByValue(ps);System.out.println(Server.clients.map.size());//關閉網絡,IO資源try {if (br != null) {br.close();}if (ps != null) {ps.close();}if (socket != null) {socket.close();}} catch (IOException ex) {ex.printStackTrace();}}}//將讀到的內容去掉前后協議字符,恢復成真實數據private String getRealMsg(String line) {return line.substring(CrazyitProtocol.PROTOCOL_LEN,line.length()-CrazyitProtocol.PROTOCOL_LEN);} }Client 客戶端
import javax.swing.*; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.Socket; import java.net.UnknownHostException;/*** 客戶端*/ public class Client {private static final int SERVER_PORT=8080;private Socket socket;private PrintStream ps;private BufferedReader brServer;private BufferedReader keyIn;public void init(){try{//初始化代表鍵盤的輸入流keyIn=new BufferedReader(new InputStreamReader(System.in));//連接到服務器端socket=new Socket("127.0.0.1",SERVER_PORT);//獲取該Socket對應的輸入流和輸出流ps=new PrintStream(socket.getOutputStream());brServer=new BufferedReader(new InputStreamReader(socket.getInputStream()));String tip=" ";//采用不斷循環地彈出對話框要求輸入用戶名while(true){String userName= JOptionPane.showInputDialog(tip+"輸入用戶名");//用戶輸入的用戶名前后增加協議字符串后發送ps.println(CrazyitProtocol.USER_ROUND+userName+CrazyitProtocol.USER_ROUND);//讀取服務器端的響應String result=brServer.readLine();//如果用戶名重復,則開始下一次循環if (result.equals(CrazyitProtocol.NAME_REP)){tip="用戶名重復,請重試";continue;}//服務器端登錄成功if (result.equals(CrazyitProtocol.LOGIN_SUCCESS)){break;}}}//捕獲到異常,關閉網絡資源,并退出該程序catch (UnknownHostException ex){System.out.println("找不到遠程服務器,請確定服務器已經啟動");closeRs();System.exit(1);}catch(IOException ex){System.out.println("網絡異常,請重新登錄");closeRs();System.exit(1);}//以該Socket對應的輸入流啟動ClientThread線程new ClientThread(brServer).start();}//定義一個讀取鍵盤輸出,并以網絡發送的方法private void readAndSend(){try{//不斷讀取鍵盤輸入String line=null;while ((line=keyIn.readLine())!=null){//如果發送的信號中有冒號,并以//開頭,則認為想發送私聊信息if (line.indexOf(":")>0&&line.startsWith("//")){line=line.substring(2);ps.println(CrazyitProtocol.PRIVATE_ROUND+line.split(":")[0]+CrazyitProtocol.SPLIT_SIGN+line.split(":")[1]+CrazyitProtocol.PRIVATE_ROUND);}else{ps.println(CrazyitProtocol.MSG_ROUND+line+CrazyitProtocol.MSG_ROUND);}}}catch (IOException ex){System.out.println("網絡通信異常!請重新登錄");closeRs();System.exit(1);}}//關閉Socket,輸入流,輸出流的方法private void closeRs(){try{if (keyIn!=null){ps.close();}if (brServer!=null){ps.close();}if (ps!=null){ps.close();}if (socket!=null){keyIn.close();}}catch (IOException ex){ex.printStackTrace();}}public static void main(String[] args){Client client=new Client();client.init();client.readAndSend();} }ClientThread 客戶端線程
import java.io.BufferedReader; import java.io.IOException;/*** 客戶端線程*/ public class ClientThread extends Thread {//該客戶端線程負責處理輸入流BufferedReader br=null;//使用一個網絡輸入流來創建客戶端線程public ClientThread(BufferedReader br){this.br=br;}public void run(){try{String line=null;//不斷地從輸入流中讀取數據,并將這些數據打印輸出while((line=br.readLine())!=null){System.out.println(line);}}catch (IOException ex){ex.printStackTrace();}finally {try {if (br!=null){br.close();}}catch (IOException ex){ex.printStackTrace();}}} }CrazyitMap 容器
import java.util.*;/*** map容器** @param <k>* @param <v>*/ public class CrazyitMap<k,v> {//創建一個線程安全的HashMappublic Map<k,v> map= Collections.synchronizedMap(new HashMap<k,v>());//根據value來刪除指定項public synchronized void removeByValue(Object value){for (Object key:map.keySet()){if (map.get(key)==value){map.remove(key);break;}}}//獲取所有value組成的Set集合public synchronized Set<v> valueSet(){Set<v> result=new HashSet<v>();//將map中的所有value添加到result集合中map.forEach((key,value)->result.add(value));return result;}//根據value查找keypublic synchronized k getKeyByValue(v value){//遍歷所有key組成的集合for (k key:map.keySet()){//如果指定key對應的value與被搜索的value相同,則返回對應的keyif(map.get(key)==value||map.get(key).equals(value)){return key;}}return null;}//實現put()方法,該方法不允許value重復public synchronized v put(k key,v value){//遍歷所有value組成的集合for (v val:valueSet()){//如果某個value與試圖放入集合的value相同//則拋出一個RuntimeException異常if (val.equals(value)&&val.hashCode()==value.hashCode()){throw new RuntimeException("MyMap實例不允許有重復的value");}}return map.put(key,value);} }CrazyitProtocol 接口
/*** 自定義接口*/ public interface CrazyitProtocol {//定義協議字符串的長度int PROTOCOL_LEN=2;//下面是一些協議字符串,服務器端和客戶端交換的信息都應該在前后添加這種特殊字符串String MSG_ROUND="ηθ";String USER_ROUND="∏∑";String LOGIN_SUCCESS="1";String NAME_REP="-1";String PRIVATE_ROUND="★【";String SPLIT_SIGN="卐"; }測試
1、啟動服務端
2、啟動客戶端 (上線)
?
3?、群發
4、私聊 (//名字:)
總結
以上是生活随笔為你收集整理的Java 实现局域网聊天室功能(私聊,群聊)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据结构--括号匹配检验(数据结构习题)
- 下一篇: java清除session_退出页面自动