JAVA-day13

一、目的

使用Socket實現(xiàn)群聊和私聊功能

二、功能和使用規(guī)范

  • 1.每個客戶端一個名稱
  • 2.向某一個客戶端發(fā)起私聊
  • 3.群聊
    客戶端只能向服務(wù)器端發(fā)送文件或者字符
    服務(wù)器端只能得到客戶端發(fā)來的數(shù)據(jù)
    必須客戶端和服務(wù)器端有一個規(guī)范
    客戶端的需求可以在發(fā)送的字符里面體現(xiàn)
  • 1.登錄 U+ 姓名 U+
  • 2.返回結(jié)果 成功1 失敗-1
  • 3.私聊 P+ 姓名:聊天內(nèi)容 P+
  • 4.群聊 a+ 聊天內(nèi)容 a+
  • 5.發(fā)文件 f+
  • 6.發(fā)語音 v+

三、具體實現(xiàn)

1.定義規(guī)范
public interface ChatProtocol {
    //登錄
    String LOGIN_FLAG="u+";
    //私聊
    String PRIVATE_FLAG="p+";
    //群聊
    String PUBLIC_FLAG="a+";

    //分隔符
    String SPLIT_FLAG="?";

    //成功的狀態(tài)
    String SUCCESS="1";
    String FALURE="-1";
}
2.定義UserManager類

管理所有的登錄的用戶Map<String,Socket>
判斷某個用戶是否已經(jīng)登錄

(1)保存所以用戶信息
public Map<String, Socket> users = new HashMap<>();
(2)判斷用戶是否已經(jīng)登錄
public synchronized boolean isLogined(String name) {
        //遍歷數(shù)組
        for (String key : users.keySet()) {
            if (key.equals(name)) {
                return true;
            }
        }
        return false;
    }
(3)保存當(dāng)前登錄的用戶信息
public synchronized void sava(String name, Socket socket) {
        users.put(name, socket);
    }
(4)通過用戶名找到對應(yīng)的socket
public synchronized Socket socketByName(String name) {
        return users.get(name);
    }
(5)通過socket對象找到對應(yīng)的名稱
public synchronized String nameBySocket(Socket socket) {
        for (String key : users.keySet()) {
            //取出這個key對應(yīng)的socket
            if (socket == users.get(key)) {
                return key;
            }
        }
        return null;
    }
(6)獲取所有人的socket對象
public synchronized Collection<Socket> allUsers(){
        return users.values();
    }
3.定義Server類模擬服務(wù)器端
(1)主線程管理監(jiān)聽客戶端的連接
public class Server {
    //用于保存每一個用戶對應(yīng)的姓名和socket
    public static UserManager manager=new UserManager();

                public static void main(String[] args) {
                    //創(chuàng)建ServerSocket
                    try (ServerSocket ss = new ServerSocket(8888)) {
                        //監(jiān)聽所有來連接的客戶端
                        while (true){
                            Socket socket=ss.accept();

                            //讓子線程處理這個socket
                new ServerThread(socket).start();

            }
        }catch (IOException e){

        }
    }
}
(2)子線程處理每個客戶端的輸入輸出
class ServerThread extends Thread{
    public Socket socket;
    public ServerThread(Socket socket){
        this.socket=socket;
    }
    @Override
    public void run() {
        BufferedReader br=null;
        PrintStream ps=null;
        //登錄
        //得到對應(yīng)的輸入流對象
        try {
            br=new BufferedReader(new InputStreamReader(socket.getInputStream()));

            //得到對應(yīng)的輸出流
            ps=new PrintStream(socket.getOutputStream());
(3)判斷是否是登錄
String line=null;
            while ((line=br.readLine())!=null){
                //登錄 u+....u+
                if (line.startsWith(ChatProtocol.LOGIN_FLAG)&&line.endsWith(ChatProtocol.LOGIN_FLAG)){
                    //u+jacku+
                    String name=line.substring(2,line.length()-2);

                    //判斷這個用戶是否已經(jīng)登錄
                    if (Server.manager.isLogined(name)){
                        //登錄過了
                        //發(fā)送結(jié)果給客戶端
                        ps.println(ChatProtocol.FALURE);
                    }else{
                        //沒有登錄
                        //保存當(dāng)前登錄的用戶信息
                        System.out.println(name+"已登錄");
                        Server.manager.sava(name,socket);
                        //發(fā)送結(jié)果給客戶端
                        ps.println(ChatProtocol.SUCCESS);
                    }
                }
(4)私聊
//判斷是不是私聊
                else if (line.startsWith(ChatProtocol.PRIVATE_FLAG)&&line.endsWith(ChatProtocol.PRIVATE_FLAG)){
                    //p+jack?hellop+
                    //獲取信息
                    String msg=line.substring(2,line.length()-2);
                    //分割 jack hello
                    String[] items=msg.split(ChatProtocol.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);
                }
(5)群聊
else {
                    //群聊
                    //
                    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 tempps=new PrintStream(s.getOutputStream());
                        tempps.println(currentName+":"+msg);
                        //tempps.close();
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
4.定義Client類模擬客戶端
(1)主線程
public class Client {
    public static void main(String[] args) {
        BufferedReader br=null;
        PrintStream ps=null;
        BufferedReader brServer=null;
        //連接服務(wù)器
        try (Socket socket = new Socket("10.129.11.163", 9300)) {
            //登錄
            //接收終端收入流
            br=new BufferedReader(new InputStreamReader(System.in));
            //發(fā)給服務(wù)器的輸出流
            ps=new PrintStream(socket.getOutputStream());
            //接收服務(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=ChatProtocol.LOGIN_FLAG+line+ChatProtocol.LOGIN_FLAG;
                //發(fā)送給服務(wù)器端
                ps.println(loginStr);
                //接收服務(wù)器端返回的結(jié)果
                String result=brServer.readLine();

                //判斷登錄結(jié)果
                if (result.equals(ChatProtocol.SUCCESS)){
                    System.out.println(line+"登陸成功");
                    break;
                }else{
                    System.out.println("用戶名以存在 請重新登錄");
                }
            }
            //登錄成功
            //開啟線程處理服務(wù)器端的輸入
            new ClientThread(socket).start();

            //接收終端輸入 發(fā)送給服務(wù)器端
            String line=null;
            while ((line=br.readLine())!=null){
                //發(fā)送給服務(wù)器
                ps.println(line);
            }

        }catch (IOException e){

        }
    }
}
(2)子線程
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){

            }
        }
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 網(wǎng)絡(luò)編程 客戶端實現(xiàn)登錄 私聊和群聊 內(nèi)容 1.建立多個客戶端2.向某一個客戶端發(fā)起私聊3.實現(xiàn)客戶端的群聊必須客...
    欲擒故縱_a222閱讀 216評論 0 0
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,641評論 1 32
  • 計算機網(wǎng)絡(luò)概述 網(wǎng)絡(luò)編程的實質(zhì)就是兩個(或多個)設(shè)備(例如計算機)之間的數(shù)據(jù)傳輸。 按照計算機網(wǎng)絡(luò)的定義,通過一定...
    蛋炒飯_By閱讀 1,365評論 0 10
  • 點擊查看原文 Web SDK 開發(fā)手冊 SDK 概述 網(wǎng)易云信 SDK 為 Web 應(yīng)用提供一個完善的 IM 系統(tǒng)...
    layjoy閱讀 14,306評論 0 15
  • 一、Python簡介和環(huán)境搭建以及pip的安裝 4課時實驗課主要內(nèi)容 【Python簡介】: Python 是一個...
    _小老虎_閱讀 6,324評論 0 10

友情鏈接更多精彩內(nèi)容