Netty的TCP_NODELAY选项
文章很长,而且持续更新,建议收藏起来,慢慢读!疯狂创客圈总目录 博客园版 为您奉上珍贵的学习资源 :
免费赠送 :《尼恩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;
}
Netty的TCP选项
Option.TCP_NODELAY
TCP/IP协议中,无论发送多少数据,总是要在数据前面加上协议头,同时,对方接收到数据,也需要发送ACK表示确认。
为了尽可能的利用网络带宽,TCP总是希望尽可能的发送足够大的数据。
TCP/IP协议中,无论发送多少数据,总是要在数据前面加上协议头,
同时,对方接收到数据,也需要发送ACK表示确认。
为了尽可能的利用网络带宽,TCP总是希望尽可能的发送足够大的数据。(一个连接会设置MSS参数,因此,TCP/IP希望每次都能够以MSS尺寸的数据块来发送数据)。
MTU:一个网络包的最大长度,以太网中一般为 1500 字节;
MSS:除去 IP 和 TCP 头部之后,一个网络包所能容纳的 TCP 数据的最大长度; 最大 1460
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内核会对每一个连接做动态的 调整, 一般情况下足够智能, 如果设置死了, 就失去了这个特性, 尤其是大量长连接的应用,
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