網(wǎng)絡(luò):QQ登路 私聊 群聊

  • QQ群:
  • 功能:私聊
  • 好友
  • 拍照
  • 拍視頻
  • 視頻通話
  • 發(fā)文件
  • QQ空間
  • 1.每個客戶端有個名稱
  • 2.私聊 向一個客戶端發(fā)起私聊
  • 3.群聊
  • 4.發(fā)文件
  • 客戶端只能像服務(wù)器端發(fā)送文件或字符
  • 服務(wù)器端只能得到客戶端發(fā)過來的數(shù)據(jù)
  • 必須客戶端和服務(wù)器端有一個規(guī)范
  • 客戶端的需求可以再發(fā)送的字符里體現(xiàn)
實現(xiàn)功能:
  • 1.登陸 u+ 姓名 u+
  • 2.返回結(jié)果 成功1 失敗-1
  • 3.私聊 p+ 姓名?聊天內(nèi)容p+
  • 4.群聊 a+ 聊天內(nèi)容 a+
  • 5.發(fā)文件 f+
  • 6.發(fā)語音
定義規(guī)范
    //登陸
    String LOGIN_FLAG = "u+";
    //私聊
    String PRIVAIE_FLAG = "p+";
    //群聊
    String PUBLIC_FLAG = "a+";
    //分隔符
    String SPLIT_FLAG = "?";
    //成功失敗的狀態(tài)
    String SUNCESS="1";
    String  FAILASE="-1";

定義用戶管理

功能
  • 管理所有的登陸用戶Map<String ,Socket>
  • 判斷用戶是否登陸
  • 保存登陸用戶信息
  • 通過用戶名找到對應(yīng)的socket
  • 通過socket對象找到對應(yīng)的名稱
  • 遍歷 獲取所有人的socket對象
public class usermanager {
    //保存所有的用戶信息
    private Map<String, Socket>users=new HashMap<>();
    /**
     * 判斷用戶是否登路
     */
    public boolean isLogined(String name)
    {
        //遍歷數(shù)組
        for (String key:users.keySet())
        {
            if (key.equals(name))
            {
                return true;
            }
        }
        return false;
    }
    /**
     * 保存當(dāng)前用戶的登陸信息
     */
    public  void save (String name,Socket socket)
    {
        users.put(name,socket);
    }
    /**
      * 通過用戶名找到對應(yīng)的socket
   */
    public Socket socketByname(String name)
    {
      return  users.get(name);
    }
    /**
     * 通過socket對象找到對應(yīng)的名稱
     */
    public  String nameBySocket(Socket socket)
    {
        for (String key:users.keySet())
        {
            //取出這個key對應(yīng)的socket
            if (socket==users.get(key))
            {
                return key;
            }
        }
        return  null;
    }
    /**
     * 獲取所有人的socket對象
     */
    public synchronized Collection<Socket> AllUsers(){
        return users.values();
    }
}

定義服務(wù)器端:

  • 保存每一個用戶的姓名和Socket
  • 開啟子線程 處理客戶端數(shù)據(jù)
public class Server {
    //Map  鍵值對
    //用于保存每一個用戶的姓名和Socket
    public static usermanager manager=new usermanager();
    public static void main(String[] args){
        //創(chuàng)建ServerSocket
        try(ServerSocket ss=new ServerSocket(8989);){
            while (true)
            {
                Socket socket=ss.accept();
                //開啟子線程處理socket
                new ServerThread(socket).start();
            }
        }catch (IOException e){

        }

    }
}

服務(wù)器端?線程
  • 處理每個客戶端的輸?輸出
  • 定義socket 構(gòu)造方法
  • 獲取輸入流對象 輸出流對象
  • 實現(xiàn)功能登陸 私聊 群聊

class ServerThread  extends Thread{
    private  Socket socket;

    public ServerThread(Socket socket)
    {
        this.socket=socket;
    }
    @Override
    public void run() {
        BufferedReader br=null;
        PrintStream ps=null;
        try {
          //獲取輸入流對象
           br=new BufferedReader(new InputStreamReader(socket.getInputStream()));

           //輸出流
            ps=new PrintStream(socket.getOutputStream());
            String line=null;

            while ((line=br.readLine())!=null)
            {

        
子線程功能一 登陸 u+.....u+
  • 使用line.substring獲取對象的名稱
  • 判斷這個用戶是否登陸
  • 登陸過了
  • 發(fā)送結(jié)果給客戶端 顯示成功
  • 沒有登陸
  • 保存當(dāng)前用戶的登陸信息 重新登陸
  if (line.startsWith(ChatClass.LOGIN_FLAG)&&line.endsWith(ChatClass.LOGIN_FLAG))
                {
//                  String []items=line.substring(2).split("u+");
//                  String   name=items[0];
                    //獲取名字
                    String name=line.substring(2,line.length()-2);
                    //判斷這個用戶是否登陸
                    if (Server.manager.isLogined(name))
                    {
                        //登陸過了
                        //發(fā)送結(jié)果給客戶端
                        ps.println(ChatClass.FAILASE);
                    }else {
                        //沒有登陸
                        //保存當(dāng)前用戶的登陸信息
                        Server.manager.save(name,socket);
                        ps.println(ChatClass.SUNCESS);
                    }
                }
子線程功能二判斷私聊 p+ 姓名?聊天內(nèi)容p+
  • 獲取分割輸入流的內(nèi)容 名稱和聊天內(nèi)容
  • 找到當(dāng)前用戶名稱

               else if(line.startsWith(ChatClass.PRIVAIE_FLAG)&&line.endsWith(ChatClass.PRIVAIE_FLAG))
                {
                    //私聊    p+ 姓名?聊天內(nèi)容p+
                    //獲取信息  jack?hellow
                    String msg = line.substring(2, line.length() - 2);
                    //分割  Jack hellow
                    String[] items = msg.split(ChatClass.SPLIT_FLAG);
                    //用戶名
                    String name = items[0];
                    //聊天內(nèi)容
                    String message = items[1];
                    //通過用戶名找到對應(yīng)的socket
                    Socket desSocket = Server.manager.socketByname(name);
                    PrintStream desps = new PrintStream(desSocket.getOutputStream());
                    //獲取當(dāng)前用戶的名稱
                    String currentName = Server.manager.nameBySocket(socket);
                    //發(fā)送私聊信息
                    desps.println(currentName + "向你發(fā)送私聊" + message);

                    //
                }
          
子線程功能三 群聊
  
                else {
                    //處理數(shù)據(jù)
                    String  msg=line.substring(2,line.length()-2);
                    //獲取當(dāng)前用戶的名稱
                    String currentName=Server.manager.nameBySocket(socket);
                    //遍歷所有的用戶信息
                    Collection<Socket> sockets=Server.manager.AllUsers();
                    for (Socket s:sockets)
                   {
                    PrintStream temps=new PrintStream(s.getOutputStream());
                    temps.println(currentName+"發(fā)來群聊"+msg);

                   }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

定義客戶端

  • 連接服務(wù)器
  • 發(fā)給服務(wù)器端的輸出流 接受終端的輸入流 接受服務(wù)器端的輸入流
  • 接受終端輸入 發(fā)送個服務(wù)端 接收服務(wù)器返滬的結(jié)果 判斷登陸結(jié)果
  • 如果登陸成功
  • 開啟線程處理服務(wù)器端的輸入
public class Client {
    public static void main(String[] args){
        BufferedReader br=null;
        PrintStream ps=null;
        BufferedReader brServer=null;
        //連接服務(wù)器
        try(Socket socket=new Socket("192.168.43.164",8989))
        {
            //發(fā)給服務(wù)器端的輸出流
            ps=new PrintStream(socket.getOutputStream());
            //接受終端的輸入流
            br=new BufferedReader(new InputStreamReader(System.in));
            //接受服務(wù)器端的輸入流
            brServer =new BufferedReader(new InputStreamReader(socket.getInputStream()));
            while (true)
            {
                //接受終端輸入
//                BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
//                String line =br.readLine();
                String line = JOptionPane.showInputDialog("請輸入姓名");
                //拼接登陸格式
                String loginStr=ChatClass.LOGIN_FLAG+line+ChatClass.LOGIN_FLAG;
                //發(fā)送個服務(wù)端
                ps.println(loginStr);

                //接收服務(wù)器返滬的結(jié)果
                String result=brServer.readLine();
                //判斷登陸結(jié)果
                if (result.equals(ChatClass.SUNCESS))
                {
                    System.out.println("登陸已成功");
                    break;
                }else {
                    System.out.println("用戶已存在  請重新輸入");
                }
            }
             //登陸成功
            //開啟線程處理服務(wù)器端的輸入
            new ClientThread(socket).start();
           String line=null;

           while ((line =br.readLine())!=null)
           {
               ps.println(line);
           }
        }catch (IOException e){

        }

   }
}
定義客戶端子線程
  • 獲取服務(wù)器端的輸出流 并輸出
class ClientThread  extends Thread{
    private Socket socket;
    public ClientThread(Socket socket)
    {
        this.socket=socket;
    }
    @Override
    public void run() {
        BufferedReader br=null;
        try{
            br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String line=null;
            while ((line =br.readLine())!=null)
            {
                System.out.println(line);
            }
        }catch (IOException e)
        {
            System.out.println("網(wǎng)絡(luò)出錯");
        }finally {
            try{
                if (br!=null)
                {
                       br.close();
                }
                if (socket!=null)
                {
                    socket.close();
                }
            }catch (IOException e)
            {
                e.printStackTrace();
            }

        }
    }
}

QQ功能.jpg

感悟:雖然這個程序敲的我一臉迷糊贰盗,不明所以,但是當(dāng)程序成功運行時童太,心里是非常的高興,敲三百多行代碼的辛苦书释,換回了運行成功的幾行代碼,為的就是那一刻的成就感爆惧。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市扯再,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌熄阻,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,376評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件秃殉,死亡現(xiàn)場離奇詭異,居然都是意外死亡钾军,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評論 2 385
  • 文/潘曉璐 我一進店門吏恭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人樱哼,你說我怎么就攤上這事哀九〈浇福” “怎么了?”我有些...
    開封第一講書人閱讀 156,966評論 0 347
  • 文/不壞的土叔 我叫張陵盏筐,是天一觀的道長。 經(jīng)常有香客問我琢融,道長,這世上最難降的妖魔是什么漾抬? 我笑而不...
    開封第一講書人閱讀 56,432評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮纳令,結(jié)果婚禮上克胳,老公的妹妹穿的比我還像新娘。我一直安慰自己圈匆,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,519評論 6 385
  • 文/花漫 我一把揭開白布跃赚。 她就那樣靜靜地躺著,像睡著了一般纬傲。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上叹括,一...
    開封第一講書人閱讀 49,792評論 1 290
  • 那天,我揣著相機與錄音领猾,去河邊找鬼。 笑死摔竿,一個胖子當(dāng)著我的面吹牛面粮,可吹牛的內(nèi)容都是我干的继低。 我是一名探鬼主播,決...
    沈念sama閱讀 38,933評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼袁翁,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了粱胜?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,701評論 0 266
  • 序言:老撾萬榮一對情侶失蹤焙压,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后涯曲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體野哭,經(jīng)...
    沈念sama閱讀 44,143評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡拨黔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,488評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了篱蝇。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贺待。...
    茶點故事閱讀 38,626評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡态兴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出瞻润,到底是詐尸還是另有隱情甜刻,我是刑警寧澤绍撞,帶...
    沈念sama閱讀 34,292評論 4 329
  • 正文 年R本政府宣布傻铣,位于F島的核電站,受9級特大地震影響祥绞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蜕径,卻給世界環(huán)境...
    茶點故事閱讀 39,896評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望兜喻。 院中可真熱鬧,春花似錦朴皆、人聲如沸帕识。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽扒接。三九已至,卻和暖如春珠增,著一層夾襖步出監(jiān)牢的瞬間超歌,已是汗流浹背蒂教。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留凝垛,地道東北人蜓谋。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像炭分,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子捧毛,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,494評論 2 348

推薦閱讀更多精彩內(nèi)容