[问题求助]关于网络编程的一个疑问,恳请大佬解释一下,无比感激!

/ 默认分类 / 0 条评论 / 910浏览

最近在看rabbitmq java客户端的源码,里面的通信方式是封装了socket,其中发送帧数据的时候有一个flush输出流的操作,我比较好奇的是flush之前是不是数据会放在缓冲区,当大小达到阈值或者手动close或者flush了会将绑定的流写出,下面是我写的一个简单的demo,虽然我有了解过网络编程的一些知识,但是暴露的问题让我实在很难弄明白,希望大佬给点指点,谢谢!

服务端8080 客户端不设置tcp连接参数,按照默认值连接和发送数据 数据长度为11

服务端在客户端wirte之后就能立刻读取到数据,不需要等到客户端关闭套接字

public class MyServer1 {

    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8080);
        System.out.println("服务端已创建");
        while (true){
            System.out.println("等待客户端连接");
            Socket socket = serverSocket.accept();
            System.out.println(new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss").format(new Date()) + "-" +"客户端已经连接,新开线程处理");
            new Thread(() -> {
                try {
                    byte[] buffer = new byte[1024];
                    System.out.println(new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss").format(new Date()) + "-" +Thread.currentThread().getName()+"线程准备读取客户端数据");
                    InputStream inputStream = socket.getInputStream();
                    System.out.println(new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss").format(new Date()) + "-" +"读取到的数据大小:"+inputStream.read(buffer));
                    System.out.println(new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss").format(new Date()) + "-" +Thread.currentThread().getName()+"读取数据段数据完毕,内容如下:");
                    System.out.println(new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss").format(new Date()) + "-" +new String(buffer));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}
public class MyClient1 {
    public static void main(String[] args)  {
        String a = "01234567899";
        Socket socket = null;
            try{
                socket = new Socket();
                socket.connect(new InetSocketAddress("127.0.0.1",8080));
                System.out.println(socket+"客户端已经连接上服务端,准备发送数据...");
            }catch(Exception e)
            {
                System.out.println(socket+"连接异常,可能是服务端sync queue已满,"+e.getMessage());
            }
            try {
                OutputStream outputStream = socket.getOutputStream();
                outputStream.write(a.getBytes());
                System.out.println(new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss").format(new Date()) + "-" +socket+"客户端已经write数据完毕,现在睡5s后再close");
                System.out.println(new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss").format(new Date())  +"-"+"sleep start");
                TimeUnit.SECONDS.sleep(5);
                System.out.println(new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss").format(new Date()) +"-"+"sleep over,close()");
                socket.close();
            } catch (Exception e) {
                System.out.println(socket+"客户端发送数据失败,"+e.getMessage());
            }
        }
    }
Socket[addr=/127.0.0.1,port=8080,localport=55280]客户端已经连接上服务端,准备发送数据...
2021-08-19 16:12:03-Socket[addr=/127.0.0.1,port=8080,localport=55280]客户端已经write数据完毕,现在睡5s后再close
2021-08-19 16:12:03-sleep start
2021-08-19 16:12:08-sleep over,close()

-------------

服务端已创建
等待客户端连接
2021-08-19 16:12:03-客户端已经连接,新开线程处理
等待客户端连接
2021-08-19 16:12:03-Thread-0线程准备读取客户端数据
读取到的数据大小:11 -2021-08-19 16:12:03
2021-08-19 16:12:03-Thread-0读取数据段数据完毕,内容如下:
2021-08-19 16:12:03-01234567899

服务端8080 客户端不设置tcp连接参数,按照默认值连接和发送数据 数据长度为10

服务端在客户端关闭套接字之后才读取到数据

public class MyServer1 {

    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8080);
        System.out.println("服务端已创建");
        while (true){
            System.out.println("等待客户端连接");
            Socket socket = serverSocket.accept();
            System.out.println(new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss").format(new Date()) + "-" +"客户端已经连接,新开线程处理");
            new Thread(() -> {
                try {
                    byte[] buffer = new byte[1024];
                    System.out.println(new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss").format(new Date()) + "-" +Thread.currentThread().getName()+"线程准备读取客户端数据");
                    InputStream inputStream = socket.getInputStream();
                    System.out.println(new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss").format(new Date()) + "-" +"读取到的数据大小:"+inputStream.read(buffer));
                    System.out.println(new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss").format(new Date()) + "-" +Thread.currentThread().getName()+"读取数据段数据完毕,内容如下:");
                    System.out.println(new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss").format(new Date()) + "-" +new String(buffer));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}
public class MyClient1 {
    public static void main(String[] args)  {
        String a = "1234567899";
        Socket socket = null;
            try{
                socket = new Socket();
                socket.connect(new InetSocketAddress("127.0.0.1",8080));
                System.out.println(socket+"客户端已经连接上服务端,准备发送数据...");
            }catch(Exception e)
            {
                System.out.println(socket+"连接异常,可能是服务端sync queue已满,"+e.getMessage());
            }
            try {
                OutputStream outputStream = socket.getOutputStream();
                outputStream.write(a.getBytes());
                System.out.println(new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss").format(new Date()) + "-" +socket+"客户端已经write数据完毕,现在睡5s后再close");
                System.out.println(new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss").format(new Date())  +"-"+"sleep start");
                TimeUnit.SECONDS.sleep(5);
                System.out.println(new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss").format(new Date()) +"-"+"sleep over,close()");
                socket.close();
            } catch (Exception e) {
                System.out.println(socket+"客户端发送数据失败,"+e.getMessage());
            }
        }
    }
Socket[addr=/127.0.0.1,port=8080,localport=55206]客户端已经连接上服务端,准备发送数据...
2021-08-19 16:13:46-Socket[addr=/127.0.0.1,port=8080,localport=55206]客户端已经write数据完毕,现在睡5s后再close
2021-08-19 16:13:46-sleep start
2021-08-19 16:13:51-sleep over,close()

-------------

服务端已创建
等待客户端连接
2021-08-19 16:13:46-客户端已经连接,新开线程处理
等待客户端连接
2021-08-19 16:13:46-Thread-0线程准备读取客户端数据
读取到的数据大小:10 -2021-08-19 16:13:51
2021-08-19 16:13:51-Thread-0读取数据段数据完毕,内容如下:
2021-08-19 16:13:51-1234567899

服务端8081 客户端不设置tcp连接参数,按照默认值连接和发送数据 数据长度为10

服务端在客户端wirte之后就能立刻读取到数据,不需要等到客户端关闭套接字

public class MyServer1 {

    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8081);
        System.out.println("服务端已创建");
        while (true){
            System.out.println("等待客户端连接");
            Socket socket = serverSocket.accept();
            System.out.println(new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss").format(new Date()) + "-" +"客户端已经连接,新开线程处理");
            new Thread(() -> {
                try {
                    byte[] buffer = new byte[1024];
                    System.out.println(new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss").format(new Date()) + "-" +Thread.currentThread().getName()+"线程准备读取客户端数据");
                    InputStream inputStream = socket.getInputStream();
                    System.out.println(new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss").format(new Date()) + "-" +"读取到的数据大小:"+inputStream.read(buffer));
                    System.out.println(new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss").format(new Date()) + "-" +Thread.currentThread().getName()+"读取数据段数据完毕,内容如下:");
                    System.out.println(new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss").format(new Date()) + "-" +new String(buffer));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}
public class MyClient1 {
    public static void main(String[] args)  {
        String a = "1234567899";
        Socket socket = null;
            try{
                socket = new Socket();
                socket.connect(new InetSocketAddress("127.0.0.1",8081));
                System.out.println(socket+"客户端已经连接上服务端,准备发送数据...");
            }catch(Exception e)
            {
                System.out.println(socket+"连接异常,可能是服务端sync queue已满,"+e.getMessage());
            }
            try {
                OutputStream outputStream = socket.getOutputStream();
                outputStream.write(a.getBytes());
                System.out.println(new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss").format(new Date()) + "-" +socket+"客户端已经write数据完毕,现在睡5s后再close");
                System.out.println(new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss").format(new Date())  +"-"+"sleep start");
                TimeUnit.SECONDS.sleep(5);
                System.out.println(new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss").format(new Date()) +"-"+"sleep over,close()");
                socket.close();
            } catch (Exception e) {
                System.out.println(socket+"客户端发送数据失败,"+e.getMessage());
            }
        }
    }
Socket[addr=/127.0.0.1,port=8081,localport=50308]客户端已经连接上服务端,准备发送数据...
2021-08-19 16:14:52-Socket[addr=/127.0.0.1,port=8081,localport=50308]客户端已经write数据完毕,现在睡5s后再close
2021-08-19 16:14:52-sleep start
2021-08-19 16:14:57-sleep over,close()

-------------

服务端已创建
等待客户端连接
2021-08-19 16:14:52-客户端已经连接,新开线程处理
等待客户端连接
2021-08-19 16:14:52-Thread-0线程准备读取客户端数据
读取到的数据大小:10 -2021-08-19 16:14:52
2021-08-19 16:14:52-Thread-0读取数据段数据完毕,内容如下:
2021-08-19 16:14:52-1234567899

疑问: 这里我尝试过设置tcp传输的参数,比如设置TcpNoDelay为true,设置sendbuffer的大小但是都没有起作用 ,我疑惑的地方就是为什么大小11是一个限制,如果11是缓冲区的大小,默认写满缓冲区之后就自动发送数据,那么换了端口 之后又怎样解释呢?为什么可以直接发送,不需要等待close();

另外如果发送的是单个中文字符,比如'一',那么也是不需要等待关闭套接字服务端就可以读取到数据,这个我觉得应该就是 字符编码的问题,导致单个中文字符编码后大小超过发送缓冲区大小(和Nagle算法有关系吗?如果有为什么我设置TcpNoDelay却没有作用)