zl程序教程

您现在的位置是:首页 >  云平台

当前栏目

Netty的TCP_NODELAY选项

TCP 选项 Netty
2023-09-11 14:13:56 时间

文章很长,而且持续更新,建议收藏起来,慢慢读!疯狂创客圈总目录 博客园版 为您奉上珍贵的学习资源 :

免费赠送 :《尼恩Java面试宝典》 持续更新+ 史上最全 + 面试必备 2000页+ 面试必备 + 大厂必备 +涨薪必备
免费赠送 经典图书:《Java高并发核心编程(卷1)加强版》 面试必备 + 大厂必备 +涨薪必备 加尼恩免费领
免费赠送 经典图书:《Java高并发核心编程(卷2)加强版》 面试必备 + 大厂必备 +涨薪必备 加尼恩免费领
免费赠送 经典图书:《Java高并发核心编程(卷3)加强版》 面试必备 + 大厂必备 +涨薪必备 加尼恩免费领
免费赠送 经典图书:尼恩Java面试宝典 最新版 面试必备 + 大厂必备 +涨薪必备 加尼恩免费领
免费赠送 资源宝库: Java 必备 百度网盘资源大合集 价值>10000元 加尼恩领取


Netty的TCP选项的配置

DefaultSocketChannelConfig

    @SuppressWarnings("unchecked")
    @Override
    public <T> T getOption(ChannelOption<T> option) {
        if (option == SO_RCVBUF) {
            return (T) Integer.valueOf(getReceiveBufferSize());
        }
        if (option == SO_SNDBUF) {
            return (T) Integer.valueOf(getSendBufferSize());
        }
        if (option == TCP_NODELAY) {
            return (T) Boolean.valueOf(isTcpNoDelay());
        }
        if (option == SO_KEEPALIVE) {
            return (T) Boolean.valueOf(isKeepAlive());
        }
        if (option == SO_REUSEADDR) {
            return (T) Boolean.valueOf(isReuseAddress());
        }
        if (option == SO_LINGER) {
            return (T) Integer.valueOf(getSoLinger());
        }
        if (option == IP_TOS) {
            return (T) Integer.valueOf(getTrafficClass());
        }
        if (option == ALLOW_HALF_CLOSURE) {
            return (T) Boolean.valueOf(isAllowHalfClosure());
        }

        return super.getOption(option);
    }

    @Override
    public <T> boolean setOption(ChannelOption<T> option, T value) {
        validate(option, value);

        if (option == SO_RCVBUF) {
            setReceiveBufferSize((Integer) value);
        } else if (option == SO_SNDBUF) {
            setSendBufferSize((Integer) value);
        } else if (option == TCP_NODELAY) {
            setTcpNoDelay((Boolean) value);
        } else if (option == SO_KEEPALIVE) {
            setKeepAlive((Boolean) value);
        } else if (option == SO_REUSEADDR) {
            setReuseAddress((Boolean) value);
        } else if (option == SO_LINGER) {
            setSoLinger((Integer) value);
        } else if (option == IP_TOS) {
            setTrafficClass((Integer) value);
        } else if (option == ALLOW_HALF_CLOSURE) {
            setAllowHalfClosure((Boolean) value);
        } else {
            return super.setOption(option, value);
        }

        return true;
    }

说明:本文会以pdf格式持续更新,更多最新尼恩3高pdf笔记,请从下面的链接获取:语雀 或者 码云

Netty的TCP选项

Option.TCP_NODELAY

TCP/IP协议中,无论发送多少数据,总是要在数据前面加上协议头,同时,对方接收到数据,也需要发送ACK表示确认。

为了尽可能的利用网络带宽,TCP总是希望尽可能的发送足够大的数据。

TCP/IP协议中,无论发送多少数据,总是要在数据前面加上协议头,

同时,对方接收到数据,也需要发送ACK表示确认。

为了尽可能的利用网络带宽,TCP总是希望尽可能的发送足够大的数据。(一个连接会设置MSS参数,因此,TCP/IP希望每次都能够以MSS尺寸的数据块来发送数据)。

MTU:一个网络包的最大长度,以太网中一般为 1500 字节;
MSS:除去 IP 和 TCP 头部之后,一个网络包所能容纳的 TCP 数据的最大长度; 最大 1460

img

Nagle算法的改进在于:

  • 如果发送端欲多次发送小数据包(长度小于MSS的数据包为小包),则发送端会先将第一个小包发送出去,而将后面到达的少量字符数据都缓存起来而不立即发送,直到收到接收端对前一个数据包报文段的ACK确认、或当前字符属于紧急数据,再发送小包

  • 或者积攒到了一定数量的数据(比如缓存的字符数据已经达到MSS数据包报文段的最大长度),将其组成一个较大的数据包发送出去。

Nagle算法(Nagle algorithm),这是使用它的发明人John Nagle的名字来命名的,John Nagle在1984年首次用这个算法来尝试解决福特汽车公司的网络拥塞问题(RFC 896)。

Nagle算法就是为了尽可能发送大块数据,避免网络中充斥着许多小数据块。

Nagle算法的基本定义是任意时刻,最多只能有一个未被确认的小段。

所谓“小段”,指的是小于MSS尺寸的数据块,

所谓“未被确认”,是指一个数据块发送出去后,没有收到对方发送的ACK确认该数据已收到。

举个例子,比如之前的blog中的实验,

一开始client端调用socket的write操作将一个int型数据(称为A块)写入到网络中,由于此时连接是空闲的(也就是说还没有未被确认的小段),因此这个int型数据会被马上发送到server端,

接着,client端又调用write操作写入‘/r/n’(简称B块),这个时候,A块的ACK没有返回,

所以可以认为已经存在了一个未被确认的小段,所以B块没有立即被发送,一直等待A块的ACK收到(大概40ms之后),B块才被发送。

整个过程如图所示:

在这里插入图片描述

这里还隐藏了一个问题,就是A块数据的ACK为什么40ms之后才收到?

这是因为TCP/IP中不仅仅有nagle算法,还有一个 ACK延迟机制 。

当Server端收到数据之后,它并不会马上向client端发送ACK,而是会将ACK的发送延迟一段时间(假设为t),

它希望提升性能:

在t时间内server端会向client端发送应答数据,这样ACK就能够和应答数据一起发送,就像是应答数据捎带着ACK过去。

在我之前的时间中,t大概就是40ms。这就解释了为什么'/r/n'(B块)总是在A块之后40ms才发出。

如果你觉着nagle算法太捣乱了,那么可以通过设置TCP_NODELAY将其禁用 。

当然,更合理的方案还是应该使用一次大数据的写操作,而不是多次小数据的写操作。

Option.SO_RCVBUF

Option(Option.SO_RCVBUF, XX),

recv_buf 不会预先分配内存, 只是个接收缓冲区size的最大限制,

不建议设置rcv_buf, linux内核会对每一个连接做动态的 调整, 一般情况下足够智能, 如果设置死了, 就失去了这个特性, 尤其是大量长连接的应用,

Option.SO_SNDBUF

Option(Option.SO_SNDBUF, XX),

send_buf 不会预先分配内存, 只是个发送缓冲区size的最大限制,

不建议设置send_buf , linux内核会对每一个连接做动态的 调整, 一般情况下足够智能, 如果设置死了, 就失去了这个特性, 尤其是大量长连接的应用,

说明:本文会以pdf格式持续更新,更多最新尼恩3高pdf笔记,请从下面的链接获取:语雀 或者 码云

Option.RCVBUF_ALLOCATOR

不是TCP协议选项

参考文献

https://blog.csdn.net/qq_22310551/article/details/124431034
https://blog.csdn.net/u013887008/article/details/104361380
https://article.itxueyuan.com/e196bP
https://blog.csdn.net/xiaolifeidaofirst/article/details/125218511
https://blog.csdn.net/small_engineer/article/details/124190620
https://learnku.com/articles/47193
https://www.cnblogs.com/xiaolincoding/p/12995358.html
https://blog.csdn.net/sinat_20184565/article/details/104828782
https://www.cnblogs.com/qhdziyan/p/16044974.html
http://blog.csdn.net/historyasamirror/article/details/6423235