Socket粘包问题的3种解决方案,最后一种最完美!(3)

简介: Socket粘包问题的3种解决方案,最后一种最完美!(3)

以上程序的通讯结果如下图所示:


微信图片_20220120153831.jpg


通过上述结果我们可以看出,服务器端发生了粘包和半包的问题,因为客户端发送了 10 次固定的“Hi,Java.”的消息,正常的结果应该是服务器端也接收到了 10 次固定的消息才对,但现实的结果并非如此。


粘包和半包的解决方案


粘包和半包的解决方案有以下 3 种:


  1. 发送方和接收方规定固定大小的缓冲区,也就是发送和接收都使用固定大小的 byte[] 数组长度,当字符长度不够时使用空字符弥补;


  1. 在 TCP 协议的基础上封装一层数据请求协议,既将数据包封装成数据头(存储数据正文大小)+ 数据正文的形式,这样在服务端就可以知道每个数据包的具体长度了,知道了发送数据的具体边界之后,就可以解决半包和粘包的问题了;


  1. 以特殊的字符结尾,比如以“\n”结尾,这样我们就知道结束字符,从而避免了半包和粘包问题(推荐解决方案)。


那么接下来我们就来演示一下,以上解决方案的具体代码实现。


解决方案1:固定缓冲区大小


固定缓冲区大小的实现方案,只需要控制服务器端和客户端发送和接收字节的(数组)长度相同即可。


服务器端实现代码如下:


/**
 * 服务器端,改进版本一(只负责接收消息)
 */
static class ServSocketV1 {
    private static final int BYTE_LENGTH = 1024;  // 字节数组长度(收消息用)
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(9091);
        // 获取到连接
        Socket clientSocket = serverSocket.accept();
        try (InputStream inputStream = clientSocket.getInputStream()) {
            while (true) {
                byte[] bytes = new byte[BYTE_LENGTH];
                // 读取客户端发送的信息
                int count = inputStream.read(bytes, 0, BYTE_LENGTH);
                if (count > 0) {
                    // 接收到消息打印
                    System.out.println("接收到客户端的信息是:" + new String(bytes).trim());
                }
                count = 0;
            }
        }
    }
}


客户端实现代码如下:


/**
 * 客户端,改进版一(只负责接收消息)
 */
static class ClientSocketV1 {
    private static final int BYTE_LENGTH = 1024;  // 字节长度
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1", 9091);
        final String message = "Hi,Java."; // 发送消息
        try (OutputStream outputStream = socket.getOutputStream()) {
            // 将数据组装成定长字节数组
            byte[] bytes = new byte[BYTE_LENGTH];
            int idx = 0;
            for (byte b : message.getBytes()) {
                bytes[idx] = b;
                idx++;
            }
            // 给服务器端发送 10 次消息
            for (int i = 0; i < 10; i++) {
                outputStream.write(bytes, 0, BYTE_LENGTH);
            }
        }
    }
}


以上代码的执行结果如下图所示:


微信图片_20220120153930.jpg


相关文章
|
9月前
|
网络协议 网络安全
python-- socket 粘包、实现 ssh
python-- socket 粘包、实现 ssh
|
10月前
|
存储 缓存 网络协议
Socket 如何处理粘包
Socket 如何处理粘包
48 0
|
网络协议 图形学
Socket TCP协议解决粘包、半包问题的三种解决方案
Socket TCP协议解决粘包、半包问题的三种解决方案
237 1
Socket TCP协议解决粘包、半包问题的三种解决方案
|
存储 缓存 网络协议
Windows技术篇——Socket粘包问题
Windows技术篇——Socket粘包问题
224 0
Socket粘包问题终极解决方案—Netty版(2W字)!(11)
Socket粘包问题终极解决方案—Netty版(2W字)!(11)
106 0
Socket粘包问题终极解决方案—Netty版(2W字)!(11)
Socket粘包问题终极解决方案—Netty版(2W字)!(10)
Socket粘包问题终极解决方案—Netty版(2W字)!(10)
131 0
Socket粘包问题终极解决方案—Netty版(2W字)!(9)
Socket粘包问题终极解决方案—Netty版(2W字)!(9)
171 0
Socket粘包问题终极解决方案—Netty版(2W字)!(9)
Socket粘包问题终极解决方案—Netty版(2W字)!(8)
Socket粘包问题终极解决方案—Netty版(2W字)!(8)
196 0
Socket粘包问题终极解决方案—Netty版(2W字)!(8)
|
1月前
|
安全 Java 数据处理
Python网络编程基础(Socket编程)多线程/多进程服务器编程
【4月更文挑战第11天】在网络编程中,随着客户端数量的增加,服务器的处理能力成为了一个重要的考量因素。为了处理多个客户端的并发请求,我们通常需要采用多线程或多进程的方式。在本章中,我们将探讨多线程/多进程服务器编程的概念,并通过一个多线程服务器的示例来演示其实现。
|
1月前
|
程序员 开发者 Python
Python网络编程基础(Socket编程) 错误处理和异常处理的最佳实践
【4月更文挑战第11天】在网络编程中,错误处理和异常管理不仅是为了程序的健壮性,也是为了提供清晰的用户反馈以及优雅的故障恢复。在前面的章节中,我们讨论了如何使用`try-except`语句来处理网络错误。现在,我们将深入探讨错误处理和异常处理的最佳实践。