一,常见问题

二,解决方法

三,总结

一,常见的问题

在实现聊天中会遇见一个常见的问题,就是如何判断发送消息的对象,是通过广播发送给所有注册的客户端还是和某个客户端进行私聊。

为此要解决两个问题,一是客户端的发送消息格式,二是服务器接受到之后判断是广播还是私发。

二,解决方法

在客户端我们可以要求客户在发送之前要把对象放入需要传输的消息前并用@连接,服务器通过获取完整信息得知客户端的需求是发给所有人还是单独发送,这里我们可以规定需要群发就要将发送对象写作-1,若要单独发送就将对应的编号写在发送对象中。服务器会识别你需要的对象是否创建。客户端的写入如下:

while (true) {
                String s;
                Scanner scanner = new Scanner(System.in);
                System.out.print("输入想发送的内容(-1是全体):");
                s = scanner.nextLine();
                try {
                    s += '\n';
                    os.write(s.getBytes(StandardCharsets.UTF_8));
                    os.flush();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }

那我们要如何识别编码呢,可以在服务器创建一个hashmap作为容器将客户端的编号和对应的socket接口存入,再将编号发送给对应的客户端让它知道自己的编号,我将其写入了服务器对应Runnable接口的构造函数中:

    public Map<Integer,Socket> map;
    public Socket socket;
    public OutputStream os;
    public InputStream is;
    public static int num=0;
    public int id;
public ServerThread(Map<Integer,Socket> map, Socket socket) throws Exception {
        this.socket=socket;
        this.map=map;
        this.is=socket.getInputStream();
        this.os=socket.getOutputStream();
        num++;
        this.id=num;
        map.put(this.id,this.socket);
        writeInt(id,os);
    }
public void writeInt(int i,OutputStream os) throws Exception {
        os.write(i);
        os.write(i >> 8);
        os.write(i >> 16);
        os.write(i >> 24);
        os.flush();
    }

客户端接受后就可以知道自己的编号了。

接下来是服务器在收到客户端的消息怎样根据需求进行发送,通过string类自带的spit方法就可以将其分为两个部分了,前一段为客户端需要发送的对象,后一段为发送的消息,在通过识别客户端是需要广播还是私发,遍历或者查找hashmap存储的接口进行发送消息:

    while (true) {
            int want = 0;
            while (true) {
                int a;
                try {
                    a = is.read();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                if (a == -1) break;
                byte b = (byte) a;
                if (b == '\n') {
                    bytes.add((byte) '\n');
                    newBytes = new byte[bytes.size()];
                    for (int i = 0; i < bytes.size(); i++) {
                        newBytes[i] = bytes.get(i);
                    }
                    bytes.clear();
                    break;
                } else {
                    bytes.add(b);
                }
            }
            String[] strings = new String(newBytes, StandardCharsets.UTF_8).split("@");
            System.out.println(strings[0] + strings[1]);
            want = Integer.parseInt(strings[0]);
            if (want != -1) {
                System.out.println("client" + id + "发送对象:" + want);
                System.out.println(strings[1]);
                for (Map.Entry<Integer, Socket> value : map.entrySet()) {
                    if (value.getKey() == want) {
                        try {
                            OutputStream outPut = value.getValue().getOutputStream();
                            String str = new String("Client" + id + ":");
                            outPut.write(str.getBytes());
                            outPut.write(strings[1].getBytes());
                            outPut.flush();
                        } catch (Exception e) {
                            throw new RuntimeException(e);
                        }
                    }
                }
            } else {
                System.out.println(strings[1]);
                for (Map.Entry<Integer, Socket> value : map.entrySet()) {
                    if (value.getValue() != this.socket) {
                        try {
                            OutputStream outPut = value.getValue().getOutputStream();
                            String str = new String("Client" + id + ":");
                            outPut.write(str.getBytes());
                            outPut.write(strings[1].getBytes());
                            outPut.flush();
                        } catch (Exception e) {
                            throw new RuntimeException(e);
                        }
                    }
                }
                System.out.println("广播完成");
            }
        }

以上就完成消息的私发和广播

三,总结

通过客户端的发送格式设置和服务器的识别进行广播或者私发,完成基础的通讯功能,后序还可以在此基础加入消息的加密,客户端的登录注册等功能来进一步完善。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐