实现了私聊和群聊功能的聊天工具
生活随笔
收集整理的這篇文章主要介紹了
实现了私聊和群聊功能的聊天工具
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
在前面的博客(簡單的C/S聊天室)中,我們已經提到了,采用的是多線程的方法。服務器端主線程負責不斷的偵聽端口,子線程負責接收和發送消息。客戶端主線程需要接收鍵盤消息,將其發送到服務器端,子線程需要接收服務器端發過來的消息。在這個簡易的C/S聊天室的實現中,僅僅實現了群聊的功能,沒有實現私聊。那么,本文就講實現私聊和群聊。
首先我們想到的是,消息發過來,我怎么知道是公聊消息還是私聊消息呢。所以,這里需要對消息進行處理,比如說在消息前后都加上一些特殊的字符,我們稱為協議字符。為此,我們可以定義一個接口,專門來定義協議字符。
第二個問題就是,如果是私聊信息,客戶端會將目的用戶(私聊對象)發給服務器端,那么服務器端是如何將找到那個目的用戶的呢。這里,很明顯,我們需要建立一個用戶和Socket的映射關系,所以我們采用了map,但是這里的map我們需要改進一下,因為其實我們這里不僅僅是key不能重復,而且value也不能重復,我們也需要通過value能夠查找到key,所以我們進行了改進。
還有一點針對本實現需要指出的是,服務器子線程負責接收和發送消息,這里面也包括客戶端首次建立連接的時候,需要判斷用戶名是否重復,也就是要保證key不重復,于此想對應的,客戶端在首次建立連接時,其需要進行不斷的嘗試,直到提供的名字不重復為止。
代碼如下:
import java.util.HashMap; import java.util.HashSet; import java.util.Set;public class CrazyitMap<K,V> extends HashMap<K,V> {// 根據value來刪除指定項public void removeByValue(Object value){for(Object key :keySet()){if(get(key)==value||get(key).equals(value)){remove(key);break;}}}// 獲取value集合public Set<V> valueSet(){Set<V> result=new HashSet<V>();for(Object key : keySet()){result.add(get(key));}return result;}// 重寫HashMap的put方法,該方法不允許value重復public V put(K key,V value){for(V val : valueSet()){if(val==value||val.equals(value)){throw new RuntimeException("MyMap實例中不允許有重復value");}}return super.put(key, value); }// 通過value查找keypublic K getKeyByValue(Object value){for(K key : keySet()){if(get(key)==value||get(key).equals(value)){return key;}}return null;} }
import java.io.IOException; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket;public class Server {private static final int PORT=30000;public static CrazyitMap<String,PrintStream> clients=new CrazyitMap<>();void init(){try (ServerSocket ss=new ServerSocket(PORT);){while(true){Socket s=ss.accept();new Thread(new ServerThread(s)).start();}}catch (IOException e) {// TODO Auto-generated catch blockSystem.out.println("服務器啟動失敗,是否端口被占用?");}}public static void main(String[] args) {// TODO Auto-generated method stubServer s=new Server();s.init();}}
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.Socket;public class ServerThread implements Runnable {private Socket s;private BufferedReader br=null;private PrintStream ps=null;public ServerThread(Socket s){this.s=s;}@Overridepublic void run() {// TODO Auto-generated method stubtry {br=new BufferedReader(new InputStreamReader(s.getInputStream()));ps=new PrintStream(s.getOutputStream());String content=null;while((content=br.readLine())!=null){if(content.startsWith(CrazyitProtocol.USR_ROUND) //發過來的是名字信息&&content.startsWith(CrazyitProtocol.USR_ROUND)){String userName=getRealMsg(content);if(Server.clients.containsKey(userName)) // 姓名重復{System.out.println("重復");ps.println(CrazyitProtocol.NAME_REP);}else // 姓名不重復{System.out.println("成功");Server.clients.put(userName, ps);ps.println(CrazyitProtocol.LOGIN_SUCCESS);}}else if(content.startsWith(CrazyitProtocol.PRAVITE_ROUND)&&content.startsWith(CrazyitProtocol.PRAVITE_ROUND))// 發過來的是實際的消息,且為私聊消息{String userAndMsg=getRealMsg(content);String userName=userAndMsg.split(CrazyitProtocol.SPLIT_SIGN)[0];String Msg=userAndMsg.split(CrazyitProtocol.SPLIT_SIGN)[1];// 獲取私聊用戶的輸出流Server.clients.get(userName).println(Server.clients.getKeyByValue(ps)+"悄悄的對你說"+Msg);}else // 公聊信息{String Msg=getRealMsg(content);for(PrintStream ps : Server.clients.valueSet()){ps.println(Server.clients.getKeyByValue(this.ps)+"說:"+Msg);}}}} // 捕獲異常,表明該Socket對應的客戶端已出現問題,// 所以客戶端將其對應的輸出流從Map中刪除catch (IOException e) {// TODO Auto-generated catch blockServer.clients.removeByValue(ps);try{if(br!=null){br.close();}if(ps!=null){ps.close();}if(s!=null){s.close();}}catch(IOException ex){ex.printStackTrace();}}}// 講讀到的內容去掉前后的協議字符,恢復為真實數據private String getRealMsg(String content) {// TODO Auto-generated method stubreturn content.substring(CrazyitProtocol.PROTOCOL_LEN, content.length()-CrazyitProtocol.PROTOCOL_LEN);}}
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.Socket; import java.net.UnknownHostException;import javax.swing.JOptionPane;public class Client {private static final int PORT=30000;private Socket s=null;private PrintStream ps=null;private BufferedReader brServer=null; //服務器發送過來的內容private BufferedReader keyIn=null; // 鍵盤輸入內容public void init(){try{s=new Socket("127.0.0.1",PORT);ps=new PrintStream(s.getOutputStream());keyIn=new BufferedReader(new InputStreamReader(System.in));brServer=new BufferedReader(new InputStreamReader(s.getInputStream()));// 用于在服務器端登錄,因為名字有可能重復String tip="";while(true){String userName=JOptionPane.showInputDialog(tip+"輸入用戶名");// 在用戶輸入的用戶名前后增加協議字符串后發送ps.println(CrazyitProtocol.USR_ROUND+userName+CrazyitProtocol.USR_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);}new Thread(new ClientThread(brServer)); // 子線程負責接收服務器端傳過來的消息}private void closeRs() {// TODO Auto-generated method stubtry{if(keyIn!=null){keyIn.close();}if(brServer!=null){brServer.close();}if(ps!=null){ps.close();}if(s!=null){s.close();}}catch(IOException e){e.printStackTrace();}}// 主線程的接收鍵盤消息函數public void readAndSend(){String content=null;try{while((content=keyIn.readLine())!=null){// 所發消息中以/開頭,且有:則認為是是私聊信息if(content.startsWith("/")&&content.indexOf(":")>0) {content=content.substring(1); //消息中不需要帶開頭的/content=CrazyitProtocol.PRAVITE_ROUND+content.split(":")[0]+CrazyitProtocol.SPLIT_SIGN+content.split(":")[1]+CrazyitProtocol.PRAVITE_ROUND;ps.println(content);}else // 群聊信息{content=CrazyitProtocol.MSG_ROUND+content+CrazyitProtocol.MSG_ROUND;ps.println(content);}}}catch(IOException e){System.out.println("網絡通信異常!請重新登錄!");closeRs();System.exit(1);}}public static void main(String[] args) {// TODO Auto-generated method stubClient client=new Client();client.init();client.readAndSend();}}
import java.io.BufferedReader; import java.io.IOException;public class ClientThread implements Runnable {private BufferedReader brServer=null;public ClientThread(BufferedReader brServer){this.brServer=brServer;}@Overridepublic void run() {// TODO Auto-generated method stubString content=null;try{while((content=brServer.readLine())!=null){System.out.println(content);}}catch(IOException e){e.printStackTrace();}finally{try{if(brServer!=null){brServer.close();}}catch(IOException e){e.printStackTrace();}}}}
參考資料:JAVA瘋狂講義
總結
以上是生活随笔為你收集整理的实现了私聊和群聊功能的聊天工具的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 儿子考上清华大学计算机系视频,儿子考上清
- 下一篇: Exynos 4412处理器IIC总线控