golang 安全的tcp server_Go 语言使用 TCP_NODELAY 控制发包流量

编写健壮且高性能的网络服务需要付出大量的努力。提高服务性能的方式有很多种,比如优化应用层的代码,更进一步,还可以看看垃圾回收器,操作系统,网络传输,以及部署我们服务的硬件是否有优化空间。

TCP/IP 协议栈中的一些算法会影响到服务性能。本文将简单介绍其中的 Nagle 算法,与 Nagle 算法相关的 socket 选项TCP_NODELAY,以及在 Go 语言中如何使用它。

理论

大部分平台上的 TCP 实现都提供了 socket 选项,用于控制连接生命周期,流量控制等算法。

其中一个会对网络传输性能造成影响的算法是 Nagle 算法,它在 Linux,macOS,Windows 平台默认都是打开的。

Nagle 算法的做法是:将要发送的小包合并,并延缓发送。延缓后的发送策略是,收到前一个发送出去的包的 ACK 确认包,或者一定时间后,收集了足够数量的小数据包。

Nagle 算法的目的是减少发送小包的数量,从而减小带宽,并提高网络吞吐量,付出的代价是有时会增加服务的延时。(译者 yoko 注:补充解释一下为什么减少小包的数量可以减小带宽。因为每个 TCP 包,除了包体中包含的应用层数据外,外层还要套上 TCP 包头和 IP 包头。由于应用层要发送的业务数据量是固定的,所以包数量越多,包头占用的带宽也越多)

引入的延时通常在毫秒级别,但是对于延迟敏感的服务来说,减少一些毫秒数的延迟也是值得的。

Nagle 算法所对应的 TCP socket 选项是TCP_NODELAY。开启TCP_NODELAY可以禁用 Nagle 算法。禁用 Nagle 算法后,数据将尽可能快的被发送出去。

另外,我们也可以在应用层对数据进行缓存合并发送来达到 Nagle 算法的目的(译者 yoko 注:在 Go 语言中即使用bufio.Writer。个人认为,使用bufio.Writer还有一个好处,就是减少了调用 write 系统调用的次数,但是相应的,增加了数据拷贝的开销)。

在 Go 语言中,TCP_NODELAY默认是开启的,并且标准库提供了net.SetNodelay(bool)方法来控制它。

实验

我们通过一个小实验来观察TCP_NODELAY打开和关闭时底层 TCP 包的变化。

代码逻辑十分简单,client 端连续调用 5 次conn.Write函数向 server 端发送相同的字符串GOPHER

服务端代码(server.go):

package main

import (
"bufio"
"fmt"
"log"
"net"
"strings"
)

func main() {
port := ":" + "8000"

// 创建监听
l, err := net.Listen("tcp", port)
if err != nil {
log.Fatal(err)
}
defer l.Close()

for {
// 接收新的连接
c, err := l.Accept()
if err != nil {
log.Println(err)
return
}

// 处理新的连接
go handleConnection(c)
}
}
func handleConnection(c net.Conn) {
fmt.Printf("Serving %s\n", c.RemoteAddr().String())

for {
// 读取数据
netData, err := bufio.NewReader(c).ReadString('\n')
if err != nil {
log.Println(err)
return
}

cdata := strings.TrimSpace(netData)
if cdata == "GOPHER" {
c.Write([]byte("GopherAcademy Advent 2019!"))
}

if cdata == "EXIT" {
break
}
}
c.Close()
}

客户端代码(client.go):

package main

import (
"fmt"
"log"
"net"
)

func main() {
target := "localhost:8000"

raddr, err := net.ResolveTCPAddr("tcp", target)
if err != nil {
log.Fatal(err)
}

// 和服务端建立连接
conn, err := net.DialTCP("tcp", nil, raddr)
if err != nil {
log.Fatal(err)
}

// conn.SetNoDelay(false) // 如果打开这行代码,则禁用TCP_NODELAY,打开Nagle算法

fmt.Println("Sending Gophers down the pipe...")

for i := 0; i < 5; i++ {
// 发送数据
_, err = conn.Write([]byte("GOPHER\n"))
if err != nil {
log.Fatal(err)
}
}
}

为了观察 TCP 包,首先开启抓包程序 tcpdump。为了简单,两个程序都在本机运行。我环境的内网环路网卡为lo0,不同机器上可能不同:

$sudo tcpdump -X  -i lo0 'port 8000'

然后,再打开两个终端窗口,先执行服务端程序,再执行客户端程序:

$go run server.go
$go run client.go

观察抓包结果,我们会发现每次调用 write 函数发送"GOPHER",对应的都是一个独立的 TCP 包被发送。总共有 5 个 TCP 包。以下是抓包结果,为了简单,我只贴出两个包:

....
14:03:11.057782 IP localhost.58030 > localhost.irdmi: Flags [P.], seq 15:22, ack 1, win 6379, options [nop,nop,TS val 744132314 ecr 744132314], length 7
0x0000: 4500 003b 0000 4000 4006 0000 7f00 0001 E..;..@.@.......
0x0010: 7f00 0001 e2ae 1f40 80c5 9759 6171 9822 .......@...Yaq."
0x0020: 8018 18eb fe2f 0000 0101 080a 2c5a 8eda ...../......,Z..
0x0030: 2c5a 8eda 474f 5048 4552 0a ,Z..GOPHER.
14:03:11.057787 IP localhost.58030 > localhost.irdmi: Flags [P.], seq 22:29, ack 1, win 6379, options [nop,nop,TS val 744132314 ecr 744132314], length 7
0x0000: 4500 003b 0000 4000 4006 0000 7f00 0001 E..;..@.@.......
0x0010: 7f00 0001 e2ae 1f40 80c5 9760 6171 9822 .......@...`aq."
0x0020: 8018 18eb fe2f 0000 0101 080a 2c5a 8eda ...../......,Z..
0x0030: 2c5a 8eda 474f 5048 4552 0a ,Z..GOPHER.

...

如果我们打开客户端中被注释掉的conn.SetNoDelay(false)这行代码,也即禁用掉TCP_NODELAY,开启 Nagle 算法,再次抓包,结果如下:

14:27:20.120673 IP localhost.64086 > localhost.irdmi: Flags [P.], seq 8:36, ack 1, win 6379, options [nop,nop,TS val 745574362 ecr 745574362], length 28
0x0000: 4500 0050 0000 4000 4006 0000 7f00 0001 E..P..@.@.......
0x0010: 7f00 0001 fa56 1f40 07c9 d46f a115 3444 .....V.@...o..4D
0x0020: 8018 18eb fe44 0000 0101 080a 2c70 8fda .....D......,p..
0x0030: 2c70 8fda 474f 5048 4552 0a47 4f50 4845 ,p..GOPHER.GOPHE
0x0040: 520a 474f 5048 4552 0a47 4f50 4845 520a R.GOPHER.GOPHER.

可以看到,有四个"GOPHER"被合并到了一个 TCP 包中。

结论

TCP_NODELAY并不是万能的,有好处有坏处,需要根据实际业务场景决定打开还是关闭。但是,在使用具体语言编写网络服务时,我们需要知道它是否被默认开启。

还有其他一些类似的 socket 选项,比如TCP_QUICKACKTCP_CORK等。但是由于有些 socket 选项是平台相关的,因此 Go 没有提供和TCP_NODELAY相同的方式来控制这些 socket 选项。我们可以通过一些平台相关的包来实现这一点。比如说,在类 unix 系统下,我们可以使用golang.org/x/sys/unix包中的SetsockoptInt方法。

举例:

err = unix.SetsockoptInt(fd, unix.IPPROTO_TCP, unix.TCP_QUICKACK, 1)
if err != nil {
return os.NewSyscallError("setsockopt", err)
}

最后,如果你想学习更多和 Nagle 算法相关的知识,可以看看这篇英文博客[1]

英文原文链接:Control packet flow with TCP_NODELAY in Go[2]

参考资料

[1]

英文博客: https://www.extrahop.com/company/blog/2016/tcp-nodelay-nagle-quickack-best-practices/

[2]

Control packet flow with TCP_NODELAY in Go: https://blog.gopheracademy.com/advent-2019/control-packetflow-tcp-nodelay/

推荐阅读

  • 架构系列:高并发架构的CDN知识介绍

  • Go语言中如何开启 TCP keepalive?


喜欢本文的朋友,欢迎关注“Go语言中文网”:

7877f69240927a55c2177fa84b23a08e.png

Go语言中文网启用微信学习交流群,欢迎加微信:274768166

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

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

相关文章

就业技术书文件表格_公路工程全套资料—开工施工检验等表格范本,及监理内业常用资料...

关键词&#xff1a;开工报告、 路基、排水、小桥、涵洞、水泥、沥青、混凝土、施工检验、监理、资料整理、基层&#xff0c;内业资料&#xff0c;监理资料&#xff0c;施工试验报告等。公路工程在管理、监理、施工过程中需及时、准确、完整地收集整理项目建设中各种档案资料&am…

龙神契约为什么显示服务器错误,龙神契约连服BOSS玩法介绍

龙神契约游戏中连服战场的游戏中的一个非常重要的部分&#xff0c;而其中的boss尤为重要。击杀boss玩家可以获得非常多的奖励&#xff0c;一般一下稀有材料都是可以获得的&#xff0c;所以打boss是重中之重的。今天小编简单给大家介绍一下。有兴趣的小伙伴千万不要错过。和小编…

dns电脑服务器发生故障怎么修复,电脑dns服务器发生故障怎么解决

一、DNS简介&#xff1a;DNS(Domain Name System&#xff0c;域名系统)&#xff0c;因特网上作为域名和IP地址相互映射的一个分布式数据库&#xff0c;能够使用户更方便的访问互联网&#xff0c;而不用去记住能够被机器直接读取的IP数串。通过主机名&#xff0c;最终得到该主机…

button设置disabled属性不生效_jQuery属性节点

发现了很好玩的表情可以插入嘻嘻嘻嘻嘻嘻嘻 1.attr属性操作 在jQuery中&#xff0c;可以通过attr()方法操作属性&#xff0c;可以是固有属性&#xff0c;也可以是自定义属性。1.1 设置属性值// 设置单个属性 $("div").attr("title", "我是一个div&quo…

如何知道电脑服务器操作系统,电脑如何查看服务器操作系统

电脑如何查看服务器操作系统 内容精选换一换北京时间1月3日&#xff0c;Intel处理器芯片被曝出存在严重的Meltdown和Spectre安全漏洞&#xff0c;漏洞详情如下&#xff1a;漏洞名称&#xff1a;Intel处理器存在严重芯片级漏洞漏洞编号&#xff1a;CVE-2017-5753、CVE-2017-5715…

哈哈机器人送到冰雪小镇_从小镇到上海:两代人的接力洄游 | 活动回顾

10月24日&#xff0c;在上海思南公馆&#xff0c;作家路明围绕着自己的新书《出小镇记》&#xff0c;和苏更生、景蛮蛮一起&#xff0c;向现场观众讲述了小镇和上海的故事。路明&#xff1a;我妈妈是69届的初中生&#xff0c;他们69届那些人走的时候&#xff0c;69届是一片红&a…

云服务器php版本修改,云服务器 更改php版本

云服务器 更改php版本 内容精选换一换本节操作介绍在管理控制台创建启动模板的操作步骤。每个账号在每个区域最多可创建30个启动模板。创建启动模板时&#xff0c;所有配置项均为可选。但如果缺失了创建实例的必要参数&#xff0c;例如规格、镜像类型&#xff0c;那么在使用该模…

opencv获得图片的像素宽度_使用OpenCV实现摄像头测距

原文链接&#xff1a;Find distance from camera to object using Python and OpenCV​www.pyimagesearch.com摄像头测距就是计算照片中的目标物体到相机的距离。可以使用相似三角形&#xff08;triangle similarity&#xff09;方法实现&#xff0c;或者使用更复杂但更准确的相…

ios下js复制到粘贴板_EXCEL被你忽视的粘贴板-11

这一节我们来聊聊粘贴板的用途&#xff0c;什么?你居然没用过粘贴板&#xff1f;平时只是ctrlc&#xff0c;然后ctrlv&#xff0c;好吧&#xff0c;那我们看看粘贴板到底能干些啥。1、提取区域内的内容有时我们选择一块区域发给同事&#xff0c;但当他需要编辑时发现居然是图片…

ros构建机器人运动学模型_ROS入门学习之八机器人综合应用

1.ROS机器人实例介绍(PR2,Turtlebot,HRMRP,Kungfu Arm)1).PR2:造就了ROS的机器人平台&#xff0c;完全基于ROS开发&#xff0c;功能丰富、强大2).Turtlebot:ROS社区中最流行的高性价比机器人平台&#xff0c;前后工发布三代3).Universal Robot:工业领域的协作机器人定义者4).HR…

微人事项目实战的数据库脚本_EMP微前端实战之cocos2d线上项目

团队原文&#xff1a;efoxTeam/emp​github.com一.背景目前cocos2d游戏最主要的开发方式是通过官方提供的GUI图形界面工具——creator&#xff0c;通过 creator 开发者无需关注构建本身&#xff0c;只需通过界面操作即可对游戏代码进行构建打包。但是这样也存在着以下几个问题&…

线粒体和叶绿体的基因组特点_如何组装植物叶绿体基因组

可能出现的问题&#xff1a;*个人电脑上遇到不能collect memery的情况&#xff0c;是电脑内存较少&#xff0c;建议分成用2G左右的数据进行组装。* Seed.fasta #用于起始组装的种子序列&#xff0c;NOVOPlasty安装软件目录下有这个文件&#xff0c;就叫这个名字&#xff0c;作者…

f3arra1n3.4.1版本_Sysmon v11.1新版本功能测试报告

一、概述根据微软文档的介绍&#xff0c;Sysmon v11新增了监控文件删除的功能&#xff0c;并支持对删除的文件进行存储备份&#xff0c;极大提高了主机威胁检测的能力。同时增加禁用反向DNS查询的功能&#xff0c;可以有效降低噪音数据。Sysmon从v10.0到目前的v11.1共经历了5个…

maya导出fbx没动画_Maya学习方法总结

关注我&#xff0c;一起来了解建模吧&#xff01;今天小编就来总结一下Maya学习过程中遇到的困难和解决方法&#xff0c;我相信有一些应该也是普遍性问题&#xff0c;注意&#xff1a;小编说的版本是Maya2018。&#xff08;1&#xff09;一次性删除所有帧的方法import的文件如果…

dev 中 gridcontrol1 滚动条重绘_浏览器的重绘和回流(Repaint amp; Reflow)

参考文献&#xff1a;https://developers.google.com/web/fundamentals/performance/critical-rendering-path/render-tree-construction?hlzh-cn​developers.google.com你真的了解回流和重绘吗 Issue #4 chenjigeng/blog​github.com前言&#xff1a;重绘&#xff1a;由于…

矿井通风计算c语言_矿井通风机主要参数的含义

矿井通风机的作用就是把地面新鲜空气送到井下&#xff0c;供工人呼吸&#xff0c;同时把有害气体从井下排出&#xff0c;使有害气体的浓度降到对人体无害的程度&#xff0c;在现代化煤矿中称通风机为“矿井的肺脏”&#xff0c;可见其重要性。风机的参数是风机选型的唯一依据&a…

行健设计_行健要闻|“第四届‘天行健创新创业设计大赛”培训班成功举办

10月9日下午&#xff0c;由院团委主办、商学部承办第四届“天行健”创新创业设计大赛动员大会暨首场培训讲座在教学楼4-103室成功启动。院团委副书记唐典巧参加动员会&#xff0c;并颁发了第九届“挑战杯”广西大学生课外学术科技作品竞赛荣誉证书&#xff0c;动员会由商学部辅…

ip地址转换pta题目_PTA「实验2-3-5 输出华氏-摄氏温度转换表」

PTA是浙江大学设计类实验辅助教学平台。题目描述输入2个正整数lower和upper&#xff08;lower≤upper≤100&#xff09;&#xff0c;请输出一张取值范围为[lower&#xff0c;upper]、且每次增加2华氏度的华氏-摄氏温度转换表。温度转换的计算公式&#xff1a;C5(F−32)/9&#…

语言爬虫字段为空_我为什么建议前端将Python 作为第二语言?

前言本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理。作者&#xff1a; 前端劝退师PS&#xff1a;如有需要Python学习资料的小伙伴可以加点击下方链接自行获取http://note.youdao.com/noteshare?id3054c…

5 获取当前访问的控制名称_LabVIEW编程技巧:网络通信中如何获取计算机名称、IP地址等信息...

问题引出在网络通讯编程中&#xff0c;经常需要获取当前主机的名称、IP地址等信息&#xff0c;在LabVIEW中如何获取这些信息呢&#xff1f;下面以本机为例进行说明&#xff0c;先看一下本机的信息。在Windows系统中打开控制台程序&#xff0c;输入“ipconfig /all”指令&#x…