Java Day13

网络编程 客户端实现登录 私聊和群聊

内容

1.建立多个客户端
2.向某一个客户端发起私聊
3.实现客户端的群聊
必须客户端和服务器端有一个规范

  • 客户端的需求可以在发送的字符里面体现
    1.登录 u+ 姓名 u+
    2.返回结果 成功1 失败-1
    3.私聊 p+ 姓名 内容 p+
    4.群聊 群聊不加任何符号 一发消息就显示在公屏里每个人可见

代码

  • 定义一个接口,确定一套规范
public interface ChatProtocol {
    // 登录
    String LOGIN_FLAG = "u+";
    // 私聊
    String PRIVATE_FLAG = "p+";
    // 群聊
    String PUBLIC_FLAG = "a+";

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

    // 成功的状态
    String SUCCESS = "1";
    String FAILURE = "-1";
}
  • 定义UserManager类 管理所有登录用的信息
/**
 * 管理所有的登录的用户 Map
 * 判断某个用户是否已经登录
 */
public class UserManager {
    // 保存所有用户信息
    private Map users = new HashMap<>();

    /**
     * 判断用户是否已经登录
     */
    public boolean isLogined(String name){
        // 遍历数组
        for(String key : users.keySet()){
            if (key.equals(name)){
                return true;
            }
        }
        return false;
    }
    /**
     * 保存当前登录的用户信息
     */

    public void save(String name,Socket socket){
        users.put(name,socket);
    }
    /**
     * 通过用户名找到对应的socket
     */
    public Socket socketByName(String name){
        return users.get(name);
            }

    /**
     * 通过socket对象找到对应的名称
     */
    public String nameBySocket(Socket socket){
        for(String key:users.keySet()){
            // 取出这个key对应的socket
            if (socket == users.get(key)){
                return key;
            }
        }
        return null;
    }

    /**
     * 获取所有人的socket对象
     */
    public synchronized Collection allUsers(){
        return users.values();
    }
}
  • Server类
    主线程管理监听客户端的连接
public class Server {
    // 用于保存每一个用户对应的姓名和socket
    public static UserManager manager = new UserManager();

    public static void main(String[] args){
        // 创建ServerSocket
        try( ServerSocket ss = new ServerSocket(8888)) {
            // 监听所有来连接的客户端
            while (true){
                Socket socket = ss.accept();

                // 让子线程处理这个socket
                new ServerThread(socket).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

子线程处理每个客户端的输入输出

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 {
            // 1.得到对应的输入流
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            ps = new PrintStream(socket.getOutputStream());
            String line = null;

判断是不是登录

 while ((line = br.readLine())!=null){
                // 登录
                if (line.startsWith(ChatProtocol.LOGIN_FLAG)&&line.endsWith(ChatProtocol.LOGIN_FLAG)){
                    // 提取用户名
                    String name = line.substring(2,line.length()-2);

                    // 判断这个用户是否已经登录
                    if (Server.manager.isLogined(name)){
                        //登录过了
                        // 发送结果给客户端
                        ps.println(ChatProtocol.FAILURE);
                    }else {
                        // 没有登录
                        // 保存当前登录的用户信息
                        Server.manager.save(name,socket);
                        ps.println(ChatProtocol.SUCCESS);
                    }

                }

私聊

 else if(line.startsWith(ChatProtocol.PRIVATE_FLAG)&&line.endsWith(ChatProtocol.PRIVATE_FLAG)){
                 // p+jack♥hellop+
                    // 获取信息
                    String msg = line.substring(2,line.length()-2);
                    // 分割
                    String[] items = msg.split(ChatProtocol.SPLIT_FLAG);
                    // 用户名
                    String name = items[0];
                    // 聊天内容
                    String message = items[1];
                    // 通过用户名找到对应的socket
                    Socket desSocket = Server.manager.socketByName(name);
                    PrintStream desPs = new PrintStream(desSocket.getOutputStream());
                    // 获取当前用户的名称
                    String currentName = Server.manager.nameBySocket(socket);

                    // 发送私聊信息
                    desPs.println(currentName+"向你发来私聊:"+message);
                }

群聊

else {
                    //群聊
                    //处理数据
                    String msg = line.substring(2,line.length()-2);
                    // 获取当前用户的名称
                    String currentName = Server.manager.nameBySocket(socket);

                    // 遍历所有的用户信息
                    Collection sockets = Server.manager.allUsers();
                    for(Socket s:sockets){
                        PrintStream temps = new PrintStream(s.getOutputStream());
                        temps.println(currentName+":"+msg);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

客户端

public class Client {
    public static void main(String[] args){
        BufferedReader br = null;
        PrintStream ps = null ;
        BufferedReader brServer;
        try(Socket socket = new Socket("10.129.28.234",8888)) {
            ps = new PrintStream(socket.getOutputStream());
            brServer = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            br = new BufferedReader(new InputStreamReader(System.in));
            // 登录
            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;
               // 发送给服务器端

                ps.println(loginStr);
               // 接收服务器端返回的结果
                String result = brServer.readLine();
                // 判断登录结果

                if (result.equals(ChatProtocol.SUCCESS)){
                    System.out.println("登录成功");
                    break;
                }else{
                    System.out.println("用户名已存在 请重新登录");
                }
            }

            // 登录成功
            // 开启线程处理服务器的输入
            new ClientThread(socket).start();
           String line = null;
            while((line = br.readLine())!= null){
                //发送给服务器
                ps.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

子线程

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("网络出错!");
        }finally {
            try {
                if (br!=null) {
                    br.close();
                }
                if (socket != null){
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果
QQ图片20190822191344.png
QQ图片20190822191532.png

心得

今天写这个demo,一开始还能跟上,到后面就跟不上了,出了一些bug。不过还是能够懂大概的过程。后面自己按照自己的理解重新将代码推敲了一遍。总算是找出了出错的地方。修改了之后已经没问题了。自己也将代码重写了一遍,不过还是有些地方比较模糊,还是看了原代码。虽然并不能自己独立写出,不过我还是蛮高兴的。

你可能感兴趣的:(Java Day13)