瀏覽代碼

feat:数据传输使用自定义的数据包格式,使用自定义的消息对象,使用自定义的编码器和解码器,使用自定义的协议,留出扩展其他功能的空间

yang yi 2 月之前
父節點
當前提交
d71449afe9

+ 10 - 2
chat-gwng/chat-client/src/main/java/space/anyi/chatClient/Client.java

@@ -1,5 +1,8 @@
 package space.anyi.chatClient;
 
+import space.anyi.chatCommom.Encoder;
+import space.anyi.chatCommom.Message;
+
 import java.io.IOException;
 import java.net.InetSocketAddress;
 import java.nio.ByteBuffer;
@@ -25,7 +28,7 @@ public class Client {
         SocketChannel socketChannel = SocketChannel.open(inetSocketAddress);
         socketChannel.configureBlocking(false);
         //写
-        socketChannel.write(ByteBuffer.wrap("Hello World!".getBytes(StandardCharsets.UTF_8)));
+        //socketChannel.write(ByteBuffer.wrap("Hello World!".getBytes(StandardCharsets.UTF_8)));
         //读
         Selector selector = Selector.open();
         socketChannel.register(selector, SelectionKey.OP_READ);
@@ -38,7 +41,12 @@ public class Client {
             if ("exit".equals(line)){
                 break;
             }
-            socketChannel.write(ByteBuffer.wrap(line.getBytes(StandardCharsets.UTF_8)));
+            Message message = new Message();
+            message.setSource("client");
+            message.setContent(line);
+            message.setTarget("group");
+            byte[] bytes = Encoder.encode(message);
+            socketChannel.write(ByteBuffer.wrap(bytes));
         }
         //释放资源
         readHandler.exit();

+ 17 - 6
chat-gwng/chat-client/src/main/java/space/anyi/chatClient/ReadHandler.java

@@ -1,5 +1,8 @@
 package space.anyi.chatClient;
 
+import space.anyi.chatCommom.Encoder;
+import space.anyi.chatCommom.Message;
+
 import java.io.Closeable;
 import java.io.IOException;
 import java.net.SocketException;
@@ -58,12 +61,25 @@ public class ReadHandler implements Runnable, Closeable {
                         SelectableChannel channel = selectionKey.channel();
                         SocketChannel socketChannel = (SocketChannel) channel;
                         //读取数据
-                        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
+                        ByteBuffer byteBuffer = ByteBuffer.allocate(4);
                         int len = 0;
                         try {
                             len = socketChannel.read(byteBuffer);
+                            if (len > 0) {
+                                byteBuffer.flip();
+                                int size = byteBuffer.getInt();
+                                byteBuffer = ByteBuffer.allocate(size);
+                                socketChannel.read(byteBuffer);
+                                //byteBuffer.flip();
+                                Message message = Encoder.decode(byteBuffer);
+
+                                //String msg = new String(byteBuffer.array(), 0, len);
+                                System.out.println(message.getSource() + ":" + message.getContent());
+                            }
                         } catch (SocketException e) {
                             //连接意外中断导致异常
+                            //关闭客户端
+                            exit();
                             e.printStackTrace();
                             selectionKey.cancel();
                             try {
@@ -75,11 +91,6 @@ public class ReadHandler implements Runnable, Closeable {
                         } catch (IOException e) {
                             e.printStackTrace();
                         }
-                        byteBuffer.flip();
-                        if (len > 0) {
-                            String msg = new String(byteBuffer.array(), 0, len);
-                            System.out.println(msg);
-                        }
                     }
                     //处理完,移除selectionKey
                     selectionKeys.remove(selectionKey);

+ 102 - 0
chat-gwng/chat-commom/src/main/java/space/anyi/chatCommom/Encoder.java

@@ -0,0 +1,102 @@
+package space.anyi.chatCommom;
+
+import java.io.*;
+import java.nio.ByteBuffer;
+import java.util.Objects;
+
+/**
+ * @ProjectName: chat-gwng
+ * @FileName: Encoder
+ * @Author: 杨逸
+ * @Data:2025/9/23 11:21
+ * @Description: 自定义的数据编码器
+ */
+public class Encoder {
+    //防止实例化
+    private Encoder() {
+    }
+
+    /**
+     * @param message 信息
+     * @return {@code byte[] }
+     * @description: 消息编码
+     * @author: 杨逸
+     * @data:2025/09/23 11:33:20
+     * @since 1.0.0
+     */
+    public static byte[] encode(Message message) {
+        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+        ObjectOutputStream objectOutputStream = null;
+        try {
+            objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
+            objectOutputStream.writeObject(message);
+            objectOutputStream.flush();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                if (Objects.nonNull(objectOutputStream))
+                objectOutputStream.close();
+                if (Objects.nonNull(byteArrayOutputStream))
+                byteArrayOutputStream.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        byte[] bytes = byteArrayOutputStream.toByteArray();
+        int size = bytes.length;
+
+        ByteBuffer buffer = ByteBuffer.allocate(size + 4);
+        buffer.putInt(size);
+        buffer.put(bytes);
+        buffer.flip();
+
+        return buffer.array();
+    }
+
+    /**
+     * @param bytes 数据
+     * @return {@code Message }
+     * @description: 消息解码
+     * @author: 杨逸
+     * @data:2025/09/23 11:38:03
+     * @since 1.0.0
+     */
+    public static Message decode(byte[] bytes) {
+        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
+        ObjectInputStream objectInputStream = null;
+        Object object = null;
+        try {
+            objectInputStream = new ObjectInputStream(byteArrayInputStream);
+            //字节转对象
+            object = objectInputStream.readObject();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } catch (ClassNotFoundException e) {
+            e.printStackTrace();
+        }finally {
+            //关闭资源
+            try {
+                if (Objects.nonNull(objectInputStream))
+                byteArrayInputStream.close();
+                if (Objects.nonNull(objectInputStream))
+                objectInputStream.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        return (Message) object;
+    }
+
+    /**
+     * @param byteBuffer
+     * @return {@code Message }
+     * @description: 信息解码
+     * @author: 杨逸
+     * @data:2025/09/23 11:44:05
+     * @since 1.0.0
+     */
+    public static Message decode(ByteBuffer byteBuffer) {
+        return decode(byteBuffer.array());
+    }
+}

+ 37 - 0
chat-gwng/chat-commom/src/main/java/space/anyi/chatCommom/Message.java

@@ -0,0 +1,37 @@
+package space.anyi.chatCommom;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @ProjectName: chat-gwng
+ * @FileName: Message
+ * @Author: 杨逸
+ * @Data:2025/9/23 11:04
+ * @Description: 信息类
+ */
+@Data
+public class Message implements Serializable {
+    //消息类型,0:系统信息,1:用户信息
+    /**
+     * 服务端:
+     * 用户信息,表示服务端只需要转发即可,群发和私聊,不需要额外处理
+     * 服务端接受到系统信息,表示需要服务端需要继续操作,上线,下线等等操作
+     *
+     * 客户端:
+     * 用户信息,渲染展示
+     * 系统信息,根据类型进行相应操作,广播则渲染信息,下线等等
+     */
+    private int type = 0;
+    //操作,系统信息对应的具体操作
+    private int operate = -1;
+    //消息内容
+    private String content = "";
+    //信息来源
+    private String source = "";
+    //目标
+    private String target = "";
+    //时间戳
+    private Long timeStamp = System.currentTimeMillis();
+}

+ 3 - 2
chat-gwng/chat-server/src/main/java/space/anyi/chatServer/ChatServer.java

@@ -1,6 +1,7 @@
 package space.anyi.chatServer;
 
 import lombok.Data;
+import space.anyi.chatCommom.Message;
 
 import java.io.Closeable;
 import java.io.IOException;
@@ -106,7 +107,7 @@ public class ChatServer implements Runnable, Closeable {
      * @data:2025/09/22 19:25:58
      * @since 1.0.0
      */
-    public void broadcast(String msg) {
+    public void broadcast(Message msg) {
         writeHandler.broadcast(msg);
     }
 
@@ -130,7 +131,7 @@ public class ChatServer implements Runnable, Closeable {
      * @data:2025/09/22 19:32:08
      * @since 1.0.0
      */
-    public void sendMessageWithGroup(String msg,SocketChannel form){
+    public void sendMessageWithGroup(Message msg, SocketChannel form){
         writeHandler.sendMessageWithGroup(msg,form);
     }
 

+ 16 - 8
chat-gwng/chat-server/src/main/java/space/anyi/chatServer/ReadHandler.java

@@ -1,6 +1,8 @@
 package space.anyi.chatServer;
 
 import lombok.Data;
+import space.anyi.chatCommom.Encoder;
+import space.anyi.chatCommom.Message;
 
 import java.io.Closeable;
 import java.io.IOException;
@@ -50,6 +52,7 @@ public class ReadHandler implements Runnable, Closeable {
             if (isExit)break;
             int select = 0;
             try {
+                if (readSelector.isOpen())
                 select = readSelector.select(100);
             } catch (IOException e) {
                 e.printStackTrace();
@@ -61,11 +64,22 @@ public class ReadHandler implements Runnable, Closeable {
                         //拿到channel
                         SelectableChannel channel = selectionKey.channel();
                         SocketChannel socketChannel = (SocketChannel) channel;
-                        //读取数据
-                        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
+                        //读取数据,分两次,第一次读数据的大小,第二次读具体的数据
+                        ByteBuffer byteBuffer = ByteBuffer.allocate(4);
                         int len = 0;
                         try {
                             len = socketChannel.read(byteBuffer);
+                            if (len > 0) {
+                                byteBuffer.flip();
+                                int size = byteBuffer.getInt();
+                                byteBuffer = ByteBuffer.allocate(size);
+                                len = socketChannel.read(byteBuffer);
+                                //byteBuffer.flip();
+                                Message message = Encoder.decode(byteBuffer);
+                                //System.out.println(msg);
+                                //转发信息
+                                writeHandler.sendMessageWithGroup(message, socketChannel);
+                            }
                         } catch (SocketException e) {
                             //连接意外中断导致异常
                             e.printStackTrace();
@@ -80,12 +94,6 @@ public class ReadHandler implements Runnable, Closeable {
                             e.printStackTrace();
                         }
                         byteBuffer.flip();
-                        if (len > 0) {
-                            String msg = new String(byteBuffer.array(), 0, len);
-                            //System.out.println(msg);
-                            //转发信息
-                            writeHandler.sendMessageWithGroup(msg, socketChannel);
-                        }
                     }
                     //处理完,移除selectionKey
                     selectionKeys.remove(selectionKey);

+ 6 - 1
chat-gwng/chat-server/src/main/java/space/anyi/chatServer/Server.java

@@ -1,5 +1,7 @@
 package space.anyi.chatServer;
 
+import space.anyi.chatCommom.Message;
+
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.channels.SelectionKey;
@@ -29,7 +31,10 @@ public class Server {
                 break;
             }
             //服务端广播信息
-            chatServer.broadcast("服务端广播:" + msg);
+            Message message = new Message();
+            message.setContent(msg);
+            message.setTarget("group");
+            chatServer.broadcast(message);
         }
     }
 }

+ 9 - 4
chat-gwng/chat-server/src/main/java/space/anyi/chatServer/WriteHandler.java

@@ -1,6 +1,8 @@
 package space.anyi.chatServer;
 
 import lombok.Data;
+import space.anyi.chatCommom.Encoder;
+import space.anyi.chatCommom.Message;
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
@@ -34,14 +36,16 @@ public class WriteHandler {
      * @since 1.0.0
      */
     //广播
-    public void broadcast(String msg){
+    public void broadcast(Message msg){
+        msg.setSource("server");
+        byte[] bytes = Encoder.encode(msg);
         //获取所有的key
         Set<SelectionKey> keys = selector.keys();
         for (SelectionKey key : keys) {
             SocketChannel channel = (SocketChannel) key.channel();
             try {
                 //发信息
-                channel.write(ByteBuffer.wrap(msg.getBytes(StandardCharsets.UTF_8)));
+                channel.write(ByteBuffer.wrap(bytes));
             } catch (IOException e) {
                 e.printStackTrace();
             }
@@ -57,14 +61,15 @@ public class WriteHandler {
      * @since 1.0.0
      */
     //群发
-    public void sendMessageWithGroup(String msg,SocketChannel form){
+    public void sendMessageWithGroup(Message msg, SocketChannel form){
         Set<SelectionKey> keys = selector.keys();
+        byte[] bytes = Encoder.encode(msg);
         for (SelectionKey key : keys) {
             SocketChannel channel = (SocketChannel) key.channel();
             //不是信息来源才转发
             if (!channel.equals(form)) {
                 try {
-                    channel.write(ByteBuffer.wrap(msg.getBytes(StandardCharsets.UTF_8)));
+                    channel.write(ByteBuffer.wrap(bytes));
                 } catch (IOException e) {
                     e.printStackTrace();
                 }