【计算机网络】Socket的TCP_NODELAY选项与Nagle算法

news2024/11/27 20:26:08

TCP_NODELAY是一个套接字选项,用于控制TCP套接字的延迟行为。当TCP_NODELAY选项被启用时,即设置为true,就会禁用Nagle算法,从而实现TCP套接字的无延迟传输。这意味着每次发送数据时都会立即发送,不会等待缓冲区的填充或等待确认。

TCP_NODELAY选项的演示

Socket服务端代码如下:

package com.morris.socket;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * Socket 服务端,演示TCP_NODELAY
 *
 * @see java.net.SocketOptions
 */
public class TcpNoDelayServerDemo {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8090);
        while (true) {
            Socket client = serverSocket.accept();
            System.out.println("accept: " + client.getRemoteSocketAddress());
            new Thread(() -> {
                try {
                    InputStream inputStream = client.getInputStream();

                    byte[] buffer = new byte[1024];
                    while (true) {
                        int len = inputStream.read(buffer);
                        if(-1 == len) {
                            System.out.println("close: " + client.getRemoteSocketAddress());
                            inputStream.close();
                            client.close();
                            break;
                        } else {
                            System.out.print("receive: " + new String(buffer, 0, len));
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

Socket客户端代码如下:

package com.morris.socket;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

/**
 * Socket 客户端,演示TCP_NODELAY
 *
 * @see java.net.SocketOptions
 */
public class TcpNoDelayClientDemo {
    public static void main(String[] args) throws IOException {

        Socket socket = new Socket("192.168.1.11", 8099);
        socket.setTcpNoDelay(true);
        OutputStream outputStream = socket.getOutputStream();
        for (int i = 0; i < 10; i++) {
            outputStream.write((i+"\n").getBytes(StandardCharsets.UTF_8));
            outputStream.flush();
        }
        outputStream.close();
        socket.close();
    }
}

默认情况下,也就是TcpNoDelay为false,开启Nagle算法,运行结果如下:

accept: /192.168.1.10:4760
receive: 0
receive: 1
2
3
4
5
6
7
8
9

客户端发了10个报文,而服务端只收到2个,客户端在发送报文的过程中进行了合并。

下面是tcpdump抓到的服务端的报文,从中也可以清晰的看到,客户端往服务端发送了2个数据报文(Flags为PSH):

$ tcpdump tcp port 8099
19:37:53.914138 IP 192.168.1.10.4760 > 192.168.1.11.8099: Flags [S], seq 3193331081, win 64240, options [mss 1452,nop,wscale 8,nop,nop,sackOK], length 0
19:37:53.914182 IP 192.168.1.11.8099 > 192.168.1.10.4760: Flags [S.], seq 2693275116, ack 3193331082, win 29200, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0
19:37:53.925761 IP 192.168.1.10.4760 > 192.168.1.11.8099: Flags [.], ack 1, win 516, length 0
19:37:53.927131 IP 192.168.1.10.4760 > 192.168.1.11.8099: Flags [P.], seq 1:3, ack 1, win 516, length 2
19:37:53.927172 IP 192.168.1.11.8099 > 192.168.1.10.4760: Flags [.], ack 3, win 229, length 0
19:37:53.927977 IP 192.168.1.10.4760 > 192.168.1.11.8099: Flags [FP.], seq 3:21, ack 1, win 516, length 18
19:37:53.928363 IP 192.168.1.11.8099 > 192.168.1.10.4760: Flags [F.], seq 1, ack 22, win 229, length 0
19:37:53.940733 IP 192.168.1.10.4760 > 192.168.1.11.8099: Flags [.], ack 2, win 516, length 0

TcpNoDelay改为false后,也就是禁用Nagle算法,运行结果如下:

accept: /192.168.1.10:3307
receive: 0
receive: 1
receive: 2
receive: 3
4
receive: 5
6
receive: 7
receive: 8
9

客户端发了10个报文,而服务端收到了7个,客户端在发送报文的过程中允许小的数据包立即发送,尽量不合并。

下面是tcpdump抓到的服务端的报文,从中也可以清晰的看到,客户端往服务端发送了10个数据报文(Flags为PSH):

> tcpdump tcp port 8099
19:39:07.953002 IP 192.168.1.10.3307 > 192.168.1.11.8099: Flags [S], seq 2087425409, win 64240, options [mss 1452,nop,wscale 8,nop,nop,sackOK], length 0
19:39:07.953071 IP 192.168.1.11.8099 > 192.168.1.10.3307: Flags [S.], seq 1383068300, ack 2087425410, win 29200, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0
19:39:07.961935 IP 192.168.1.10.3307 > 192.168.1.11.8099: Flags [.], ack 1, win 516, length 0
19:39:07.963806 IP 192.168.1.10.3307 > 192.168.1.11.8099: Flags [P.], seq 1:3, ack 1, win 516, length 2
19:39:07.963808 IP 192.168.1.10.3307 > 192.168.1.11.8099: Flags [P.], seq 3:5, ack 1, win 516, length 2
19:39:07.963858 IP 192.168.1.11.8099 > 192.168.1.10.3307: Flags [.], ack 3, win 229, length 0
19:39:07.963867 IP 192.168.1.11.8099 > 192.168.1.10.3307: Flags [.], ack 5, win 229, length 0
19:39:07.963903 IP 192.168.1.10.3307 > 192.168.1.11.8099: Flags [P.], seq 5:7, ack 1, win 516, length 2
19:39:07.963925 IP 192.168.1.11.8099 > 192.168.1.10.3307: Flags [.], ack 7, win 229, length 0
19:39:07.963904 IP 192.168.1.10.3307 > 192.168.1.11.8099: Flags [P.], seq 7:9, ack 1, win 516, length 2
19:39:07.963933 IP 192.168.1.11.8099 > 192.168.1.10.3307: Flags [.], ack 9, win 229, length 0
19:39:07.963904 IP 192.168.1.10.3307 > 192.168.1.11.8099: Flags [P.], seq 9:11, ack 1, win 516, length 2
19:39:07.963939 IP 192.168.1.11.8099 > 192.168.1.10.3307: Flags [.], ack 11, win 229, length 0
19:39:07.964809 IP 192.168.1.10.3307 > 192.168.1.11.8099: Flags [P.], seq 11:13, ack 1, win 516, length 2
19:39:07.964810 IP 192.168.1.10.3307 > 192.168.1.11.8099: Flags [P.], seq 13:15, ack 1, win 516, length 2
19:39:07.964811 IP 192.168.1.10.3307 > 192.168.1.11.8099: Flags [P.], seq 15:17, ack 1, win 516, length 2
19:39:07.964812 IP 192.168.1.10.3307 > 192.168.1.11.8099: Flags [P.], seq 17:19, ack 1, win 516, length 2
19:39:07.964813 IP 192.168.1.10.3307 > 192.168.1.11.8099: Flags [P.], seq 19:21, ack 1, win 516, length 2
19:39:07.964861 IP 192.168.1.11.8099 > 192.168.1.10.3307: Flags [.], ack 13, win 229, length 0
19:39:07.964868 IP 192.168.1.11.8099 > 192.168.1.10.3307: Flags [.], ack 15, win 229, length 0
19:39:07.964871 IP 192.168.1.11.8099 > 192.168.1.10.3307: Flags [.], ack 17, win 229, length 0
19:39:07.964874 IP 192.168.1.11.8099 > 192.168.1.10.3307: Flags [.], ack 19, win 229, length 0
19:39:07.964878 IP 192.168.1.11.8099 > 192.168.1.10.3307: Flags [.], ack 21, win 229, length 0
19:39:07.964923 IP 192.168.1.10.3307 > 192.168.1.11.8099: Flags [F.], seq 21, ack 1, win 516, length 0
19:39:07.965196 IP 192.168.1.11.8099 > 192.168.1.10.3307: Flags [F.], seq 1, ack 22, win 229, length 0
19:39:07.974934 IP 192.168.1.10.3307 > 192.168.1.11.8099: Flags [.], ack 2, win 516, length 0

Nagle算法

TCP协议是网络编程中最重要的协议之一,TCP协议将上层的数据附上TCP报头等信息,封装成一个个报文段(segment),然后交由下层网络层去处理。TCP协议定义了TCP报文段的结构,如下图所示:

可以看出,TCP每个报文段的首部大小至少是20字节的数据,因此若用户数据为1字节,再加上网络层IP包头20字节,则整个IP数据包的大小为41字节,那么整个IP数据包的负荷率为1/41。这显然是不划算的,会降低网络的传输效率,当网络都充斥着这种IP数据包的时候,可想而知整个网络几乎都在传输一些无用的包头信息,这种问题被称为小包问题。特别是在Telnet协议中,当用户远程登录到一个主机,他的每一次键盘敲击实际上都会产生一个携带用户数据量小的数据包,这是典型的小包问题。

为了解决这种问题,出现了Nagle’s Algorithms,这个算法是John Nagle为解决实际过程中出现的小包问题而发明的。它的思想很朴素,就是将多个即将发送的小段的用户数据,缓存并合并成一个大段数据时,一次性一并发送出去。特别的是,只要当发送者还没有收到前一次发送TCP报文段的的ACK(即连接中还存在未回执ACK的TCP报文段)时,发送方就应该一直缓存数据直到数据达到可以发送的大小,然后再统一合并到一起发送出去,如果收到上一次发送的TCP报文段的ACK则立马将缓存的数据发送出去。

与之相呼应的还有一个网络优化的机制叫做TCP延迟确认,这个是针对接收方来讲的机制,由于ACK包属于有效数据比较少的小包,因此延迟确认机制就会导致接收方将多个收到数据包的ACK打包成一个回复包返回给发送方。这样就可以避免导致只包含ACK的TCP报文段过多导致网络额外的开销(前面提到的小包问题)。延迟确认机制有一个超时机制,就是当收到每一个TCP报文段后,如果该TCP报文段的ACK超过一定时间还未发送就启动超时机制,立刻将该ACK发送出去。因此延迟确认机制会可能会带来500ms的ACK延迟确认时间。

延迟确认机制和Nigle算法几乎是在同一时期提出来的,但是是由不同的组提出的。这两种机制在某种程度上的确对网络传输进行了优化,在通常的协议栈实现中,这两种机制是默认开启的。

但是,这两种机制结合起来的时候会产生一些负面的影响,可能会导致应用程序的性能下降。

TCP_NODELAY使用注意事项

Nagle算法是应用在发送端的,简而言之就是,对发送端而言:

  • 当第一次发送数据时不用等待,就算是1byte的小包也立即发送
  • 后面发送数据时需要累积数据包直到满足下面的条件之一才会继续发送数据:
    • 数据包达到最大段大小MSS
    • 接收端收到之前数据包的确认ACK

MTU是指在网络通信中能够传输的最大数据包大小。MSS一般会小于等于MTU,因为数据包中还包含有TCP/IP协议头部的额外开销。一般情况下,IPv4网络中的MTU大小为1500字节,而IPv6网络中的MTU大小为1280字节。

网卡的信息上有mtu的大小:

$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.24.104.61  netmask 255.255.240.0  broadcast 172.24.111.255
        inet6 fe80::215:5dff:fe6f:5634  prefixlen 64  scopeid 0x20<link>
        ether 00:15:5d:6f:56:34  txqueuelen 1000  (Ethernet)
        RX packets 213794  bytes 293979318 (293.9 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 106646  bytes 8514354 (8.5 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

禁用Nagle算法可以降低延迟,适用于实时性要求高的应用,如实时音视频传输或实时游戏。

禁用Nagle算法可能会导致更频繁的网络传输,增加网络开销。因此,在传输大量小数据包的情况下,禁用Nagle算法可能会降低网络效率。

TCP_NODELAY选项通常在创建套接字后设置,对于已经建立的连接,可能需要重新创建套接字并设置选项。

需要根据具体的需求和场景来决定是否使用TCP_NODELAY选项,权衡延迟和网络效率之间的关系。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1399457.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PostgreSQL命令大全

文章目录 连接与退出数据库操作表操作外键约束视图操作存储过程与函数权限管理事务管理查询优化与分析数据类型转换分区表操作复制与备份恢复 PostgreSQL是一个功能强大的开源关系型数据库管理系统&#xff0c;以下是一些基本且常用的命令按功能分类&#xff1a; 连接与退出 连…

【内存管理】flink内存管理(一):内存管理概述:flink主动管理内存原理、flink内存模型

文章目录 一.flink为什么自己管理内存1. 处理大数据时JVM内存管理的问题2. flink主动管理内存逻辑2.1. Flink内存管理方面2.2. 序列化、反序列化说明 3. Flink主动管理内存的好处 二. Flink内存模型1. 堆内存2. 非堆内存2.1. 托管内存2.2.直接内存2.3. JVM特定内存 本节从整体使…

【每日一题】2788. 按分隔符拆分字符串-2024.1.20

题目&#xff1a; 2788. 按分隔符拆分字符串 给你一个字符串数组 words 和一个字符 separator &#xff0c;请你按 separator 拆分 words 中的每个字符串。 返回一个由拆分后的新字符串组成的字符串数组&#xff0c;不包括空字符串 。 注意 separator 用于决定拆分发生的位…

循序渐进学 JavaScript <一>

这周复习完了 js 基础&#xff0c;整理一波~ 一、认识 JavaScript 1. 1 编程语言 计算机语言&#xff1a;概念比较广泛&#xff0c;包括 html 标记语言&#xff08;它并不是编程语言&#xff09;编程语言特点 具有数据和数据结构指令和流程控制&#xff1a;switch&#xff0c…

Ubuntu安装最新版Docker和Docker-Compose

ubuntu环境搭建专栏&#x1f517;点击跳转 Ubuntu系统环境搭建&#xff08;十&#xff09;——Ubuntu安装最新版Docker和Docker Compose 文章目录 Ubuntu系统环境搭建&#xff08;十&#xff09;——Ubuntu安装最新版Docker和Docker Compose1.添加Docker库1.1 安装必要的证书并…

FastDFS 环境搭建及使用详解

文章目录 1、简介1.1 分布式文件系统1.2 FastDFS1.3 FastDFS架构 2、环境搭建2.1 FastDFS安装2.1.1 安装前准备2.1.2 安装包下载2.1.3 安装 libfastcommon2.1.4 安装 libserverframe2.1.5 安装 FastDFS 2.2 FastDFS配置2.2.1 配置tracker2.2.1.1 创建 tracker 工作目录2.2.1.2 …

关于gltf模型格式文件的学习

目录 glTF模型 小黄鸭的gltf模型 字段分析 scene nodes meshes primitives attributes indices mode material accessors bufferView byteOffset count componentType type materials textures images samplers magFilter与minFilter wrapS与wrapT 进行…

好物周刊#37:元气桌面

https://github.com/cunyu1943/JavaPark https://yuque.com/cunyu1943 村雨遥的好物周刊&#xff0c;记录每周看到的有价值的信息&#xff0c;主要针对计算机领域&#xff0c;每周五发布。 一、项目 1. MallChat 一个既能购物又能聊天的电商系统。以互联网企业级开发规范的…

canvas能压缩图片?

之前写过一篇使用命令行工具压缩图片的博文&#xff1a;使用yx-tiny命令行工具进行图片压缩&#xff0c;大家感兴趣可以去瞅一眼。 这篇简单说一下使用canvas压缩图片 其实思路很简单&#xff0c;我们选择了图片之后&#xff0c;会获取到对应的文件流对象&#xff0c;然后我们…

计算机组成原理 第一弹

ps&#xff1a;本文章的图片来源都是来自于湖科大教书匠高老师的视频&#xff0c;声明&#xff1a;仅供自己复习&#xff0c;里面加上了自己的理解 这里附上视频链接地址&#xff1a;1-2 计算机的发展_哔哩哔哩_bilibili ​​ 目录 &#x1f680;计算机系统 &#x1f680;计…

中小企业如何快速融资-----股权融资的四种方式(上)

’在企业融资的多种手段中&#xff0c;股权质押融资、股权交易增值融资、股权增资扩股融资和股权的私募融资&#xff0c;逐渐成为中小企业利用股权实现融资的有效方式。随着市场体系和监管制度的完善&#xff0c;产权市场为投融资者搭建的交易平台日益成熟&#xff0c;越来越多…

【linux驱动】详细剖析第一个hello word驱动程序

文章目录 驱动程序的框架驱动程序的使用示例 驱动程序的框架 Linux 驱动的基本框架主要由模块加载函数&#xff0c;模块卸载函数&#xff0c;模块许可证声明&#xff0c;模块参数&#xff0c;模块导出符号&#xff0c;模块作者信息等几部分组成&#xff0c;其中模块参数&#…

钉钉副总裁李智勇:AI超级助理,提升大模型时代生产力

微软比尔盖茨此前曾预言:“五年内&#xff0c;每个人都将拥有AI私人助理Agent&#xff0c;Agent将颠覆软件行业 。” 近日以来&#xff0c;在GPT store正式上线点爆情绪之后&#xff0c;无论国内外&#xff0c;Agent都是创业圈里炙手可热的新贵。一场关于Agent创业比拼大赛&am…

探索JAVA神秘运行机制:揭秘JVM内存区域

目录 1. 前文回顾 2.内存区域的划分 2.1 存放类的方法区 2.2 程序计数器 2.3 Java虚拟机栈 2.4 Java堆内存 2.5 其他内存区域 3. 核心内存区域运行流程 4. 总结 1. 前文回顾 上一篇我们一起探索了Java的整体运行流程&#xff0c;类加载器以及类的加载机制&#xff0…

手把手教你使用 VS Code 运行和调试 Python 程序

本文以 Ubuntu 系统为例&#xff0c;介绍如何在 VS Code 上配置 Python 的编程环境&#xff0c;并把 Python 程序运行、调试起来。由于 Python 是解释型语言&#xff0c;并且 VS Code 中提供了内置的调试器可用于调试 Python 代码&#xff0c;因此配置和操作流程比调试 C/C 代码…

【 Qt 快速上手】-①- Qt 背景介绍与发展前景

文章目录 1.1 什么是 Qt1.2 Qt 的发展史1.3 Qt 支持的平台1.4 Qt 版本1.5 Qt 的优点1.6 Qt的应用场景1.7 Qt的成功案例1.8 Qt的发展前景及就业分析行业发展方向就业方面的发展前景 1.1 什么是 Qt Qt 是一个跨平台的 C 图形用户界面应用程序框架。它为应用程序开发者提供了建立…

8 python快速上手

总结 总结1. 代码规范1.1 名称1.2 注释1.3 todo1.4 条件嵌套1.5 简单逻辑先处理1.6 循环1.7 变量和值 2.知识补充2.1 pass2.2 is 比较2.3 位运算 3.阶段总结 各位小伙伴想要博客相关资料的话关注公众号&#xff1a;chuanyeTry即可领取相关资料&#xff01; 总结 1. 代码规范 …

线性规划案例分享

今天想写一个最优传输的简单实现&#xff0c;结果学歪了&#xff0c;学到线性规划去了&#xff0c;这里我发现了一个宝藏网站 虽然是讲计量经济的&#xff0c;但是里面提供的公式和代码我很喜欢&#xff0c;有时间可以好好读一下 https://python.quantecon.org/lp_intro.html …

Civil 3D安装教程,免费使用,带安装包和工具,一分钟轻松搞的安装

前言 Civil 3D是一款面向基础设施行业的建筑信息模型&#xff08;BIM&#xff09;解决方案。它为基础设施行业的各类技术人员提供了强大的设计、分析以及文档编制功能&#xff0c;广泛适用于勘察测绘、岩土工程、交通运输、水利水电、市政给排水、城市规划和总图设计等众多领域…

什么是比特币?

比特币 比特币 &#xff08;英语&#xff1a;Bitcoin&#xff0c;缩写&#xff1a;BTC &#xff09;是一种基于 去中心化&#xff0c;采用 点对点网络&#xff0c;开放源代码&#xff0c;以 区块链 作为底层技术的 加密货币。比特币由 中本聪&#xff08;Satoshi Nakamoto&…