TCP/UDP Socket、消息推送、自定义编码解码器(协议)

  • socket

    • Socket

      • --> 数据包经由应用程序产生

      • --> 通过协议栈进行报文头包装

      • --> 操作系统调用网卡驱动程序指挥硬件,将数据发送到对端主机 Socket在这个流程中提供了应用程序与网络层之间的接口

      • TCP Socket 面向连接的可靠传输

        • Socket 类和 ServerSocket 类

        • 通过输入输出流(InputStream和OutputStream)来发送和接收字节流。这些字节流在底层被封装成数据包,由操作系统和网络协议栈处理

      • UDP Socket 面向无连接的高效传输

        • DatagramSocket 和 DatagramPacket 两个主要类

        • DatagramPacket类表示一个UDP数据包,包含了一个字节数组以及该数组的长度,还有源和目标的IP地址和端口号。通过DatagramSocket来发送和接收DatagramPacket,从而在网络上进行UDP通信。

    • TCP Socket

      • 服务器端

        • 创建ServerSocket对象,指定端口号监听连接请求

          • ServerSocket serverSocket = new ServerSocket(portNumber);

        • 阻塞住,等待连接

          • Socket clientSocket = serverSocket.accept();

        • 获取 输入流(如InputStream或BufferedReader) 输出流(如OutputStream或PrintWriter),与客户端通信

          • BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);

        • 读写数据

          • 读取客户端发送数据

            • String inputLine = in.readLine();

          • 向客户端发送数据

            • out.println("......");

        • 关闭连接

          • clientSocket.close(); serverSocket.close();

      • 客户端

        • 创建Socket对象

          • Socket socket = new Socket(serverIP, portNumber);

        • 通过socket对象获取输入输出流

          • BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(socket.getOutputStream(), true);

        • 读写数据

          • 发送给服务端

            • out.println("......");

          • 读取服务器返回数据

            • String response = in.readLine();

        • 关闭连接

          • socket.close();

    • UDP Socket

      • 服务器端

        • 创建DatagramSocket对象 接收客户端发送数据报

          • DatagramSocket serverSocket = new DatagramSocket(portNumber);

        • 接收数据报

          • byte[] buffer = new byte[bufferSize]; DatagramPacket receivePacket = new DatagramPacket(buffer, buffer.length); serverSocket.receive(receivePacket);

        • 处理接收到的数据

          • String receivedData = new String(receivePacket.getData(), 0, receivePacket.getLength()); InetAddress senderIP = receivePacket.getAddress(); int senderPort = receivePacket.getPort();

        • 发送响应(非必要)

          • String responseData = "Received yourmsg";

          • byte[] sendData = responseData.getBytes();

          • InetAddress clientIP = receivePacket.getAddress(); // 通常使用客户端的IP地址作为目标地址 int clientPort = receivePacket.getPort(); // 通常使用客户端的端口号作为目标端口

          • DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, clientIP, clientPort); serverSocket.send(sendPacket);

        • 关闭连接 关闭DatagramSocket对象

          • serverSocket.close();

      • 客户端

        • 创建DatagramSocket对象

          • DatagramSocket clientSocket = new DatagramSocket();

        • 准备发送数据

          • String sendData = "msg from client!";

          • byte[] sendBuffer = sendData.getBytes();

          • InetAddress serverIP = InetAddress.getByName("serverIPAddress");

          • int serverPort = portNumber;

        • 发送数据报

          • DatagramPacket sendPacket = new DatagramPacket(sendBuffer, sendBuffer.length, serverIP, serverPort);

          • clientSocket.send(sendPacket);

        • 接收响应(非必要)

        • 关闭连接

          • clientSocket.close();

    • 消息推送方式

      • 轮询

        • 客户端按照固定的时间间隔(例如,每几秒或几分钟)向服务器发送请求,以检查是否有新的消息或更新。服务器响应这些请求,返回客户端所需的数据。

      • 长轮询

        • 客户端向服务器发送一个请求,然后服务器会保持这个连接打开,直到有新数据可用或者达到某个超时时间。当服务器有新数据时,它会立即将数据返回给客户端并关闭连接。如果达到超时时间但还没有新数据,服务器会发送一个空响应或特定的超时消息,然后关闭连接。客户端在收到响应后,会立即重新发起一个新的长轮询请求,以等待下一个数据更新。

      • SSE

        • 是一种服务器向客户端推送实时更新的简单方式,它基于HTTP协议,但实现了类似WebSocket的服务器推送功能。SSE使用一种简单的文本/事件流格式来发送事件,允许服务器向客户端推送更新。

      • websocket

        • 是一种在单个TCP连接上进行全双工通信的协议。它被设计用来解决传统HTTP协议中客户端向服务器发送请求、服务器响应后连接关闭的问题,从而实现了服务器可以主动向客户端推送数据的功能

    • socket.io

      • 用于实时双向通信的 JavaScript 库

      • Socket.IO 由两部分组成:

        • Socket.IO 客户端库:在浏览器或其他客户端环境中运行,用于与服务器进行实时通信。

        • Socket.IO 服务器库:在 Node.js 或其他后端环境中运行,用于处理来自客户端的连接和消息。

      • WebSocket

        • 服务端

          • 方法

            • onOpen()

              • onClose()

                • onError()

          • 注解

            • @OnOpen

              • @OnClose

                • @OnError

          • 服务端接收数据

            • MessageHandler

            • @OnMessage

          • 服务端推送数据

            • Session对象

              • 同步、异步

        • 客户端

          • 对象创建

            • let ws = new WebSocket(URL:'ws://localhost/chat');

          • 对象相关事件

            • 事件

              • 事件处理程序

                • 描述

            • open

              • ws.onopen

                • 连接建立时触发

            • message

              • ws.onmessage

                • 客户端接收到服务器发送的数据时触发

            • close

              • ws.onclose

                • 连接关闭时触发

          • 对象提供的方法

            • send();

              • 通过webSocket对象调用该方法发送数据给服务端

          • 自由主题

    • 协议设计与解析

      • Redis

        • *3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$7\r\nmyvalue\r\n

      • HTTP

        • Netty提供解码器

          • HttpRequestDecoder:将字节流解码为 HTTP 请求 HttpResponseEncoder:将 HTTP 响应编码为字节流 HttpObjectAggregator:将多个 HTTP 消息对象(例如 HTTP 请求头和内容)聚合成一个完整的 HTTP 消息

          • SimpleChannelInboundHandler<HttpRequest>()

          • 代码示例

            @Override
                public void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception {
                    // 1. 4 字节的魔数
                    out.writeBytes(new byte[]{1, 2, 3, 4});
                    // 2. 1 字节的版本,
                    out.writeByte(1);
                    // 3. 1 字节的序列化方式 jdk 0 , json 1
                    out.writeByte(0);
                    // 4. 1 字节的指令类型
                    out.writeByte(msg.getMessageType());
                    // 5. 4 个字节
                    out.writeInt(msg.getSequenceId());
                    // 无意义,对齐填充,凑偶数字节
                    out.writeByte(0xff);
                    // 6. 获取内容的字节数组
                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
                    ObjectOutputStream oos = new ObjectOutputStream(bos);
                    oos.writeObject(msg);
                    byte[] bytes = bos.toByteArray();
                    // 7. 长度
                    out.writeInt(bytes.length);
                    // 8. 写入内容
                    out.writeBytes(bytes);
                }

      • 自定义协议

        • 自定义

          • --魔数,用来在第一时间判定是否是无效数据包

          • --版本号,可以支持协议的升级

          • --序列化算法,消息正文到底采用哪种序列化反序列化方式,可以由此扩展,例如:json、protobuf、hessian、jdk

          • --指令类型,是登录、注册、单聊、群聊..跟业务相关

          • --请求序号,为了双工通信,提供异步能力

          • --正文长度

          • --消息正文

        • 自定义协议代码示例

          • 编码

             @Override
                protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
                    int magicNum = in.readInt();
                    byte version = in.readByte();
                    byte serializerType = in.readByte();
                    byte messageType = in.readByte();
                    int sequenceId = in.readInt();
                    in.readByte();
                    int length = in.readInt();
                    byte[] bytes = new byte[length];
                    in.readBytes(bytes, 0, length);
                    ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
                    Message message = (Message) ois.readObject();
                    log.debug("{}, {}, {}, {}, {}, {}", magicNum, version, serializerType, messageType, sequenceId, length);
                    log.debug("{}", message);
                    out.add(message);
                }

          • 解码(编码逆过程)

  • 21
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值