微信号:tiankonguse-code

介绍:这里是tiankonguse在代码世界里学习时的记录

了解tcp底层知识

2016-01-17 21:48 tiankonguse

背景


之前,遇到客户端因使用短连接导致连接服务失败的为问题, 后来通过配置系统参数解决了.
当时还写了一篇记录TIME_WAIT 简单记录(一).
今天再来记录一些tcp的知识吧.




目录


这篇记录主要有这些内容:


  1. 创建连接

  2. read数据

  3. write数据

  4. 拥塞控制


当然, 记录的都是概念上的东西, 有问题可以找我讨论.






创建连接



tcp 使用三次握手建立连接:


  1. 客户端向server发送SYN包

  2. server回复SYN+ACK

  3. 客户端返回ACK包


这里要记录的是连接的过程中, 服务端存在两个队列来储存状态.

  • 半连接队列
    当server回复SYN+ACK包时, 会将SYN_RECV状态的连接保存到半连接队列中
    队列长度由net.ipv4.tcp_max_syn_backlog设置

  • accept队列
    当客户端回复ACK包时, 会将ESTABLISHED状态的连接移入accept队列,等待应用调用accept()
    队列长度为min(net.core.somaxconn, backlog), backlog 为 listen函数的第二个参数.


这两个队列也引出了两个问题.

  • SYN flooding
    客户端大量的发送SYN包, 不回ACK, 这时将会把半连接队列填满, 从而会影响正常服务.
    SYN cookie可以解决这个问题.
    SYN cookie 是将连接信息编码在ISN(initial sequence number)中返回给客户端, 客户端返回ACK时,再还原连接信息即可.
    我们可以配置 net.ipv4.tcp_syncookies 来开启这个功能.

  • 大量连接
    这个问题暂时保留.




read数据



linux里面使用sk_buff数据结构来描述packet.

  • NIC(network interface controller)检测到packet到达, 从Kernel Memory(sk_buffs)分配sk_buff数据结构,调用DMA Engine将packet放到sk_buff数据结构里面, Ring Buffer里储存的是指向sk_buff的描述符.
    Ring Buffer的大小固定, 当满了的时候, 新来的packet会被丢弃.
    当DMA Engine完成处理之后, NIC通过向CPU发起中断 通知kernel进行处理。

  • kernel将这个packet传递给IP层进行处理。IP层需要将信息组装成为ip packet。
    如果ip packet是tcp的话那么放到socket backlog里面。如果socket backlog满了的话那么将ip packet丢弃。
    tcp layer从socket backlog里面取出tcp packet, 然后会回ACK确认.

  • tcp recv buffer交给application layer处理

这里面又涉及两个队列: Ring Buffer, Poll list, socket backlog.


Ring Buffer

Ring Buffer位于NIC和IP层之间,是一个典型的FIFO.

可以通过ifconfig观察接收和传输队列的运行状况:


  • RX errors:收包总的错误数

  • RX dropped: 表示数据包已经进入了Ring Buffer,但是由于内存不够等系统原因,导致在拷贝到内存的过程中被丢弃。

  • RX overruns: overruns意味着数据包没到Ring Buffer就被网卡物理层给丢弃了,而CPU无法及时的处理中断是造成Ring Buffer满的原因之一

当dropped数量持续增加,建议增大Ring Buffer,使用ethtool -G进行设置。


Input Packet Queue(数据包接收队列)


当接收数据包的速率大于内核TCP处理包的速率,数据包将会缓冲在TCP层之前的队列中。接收队列的长度由参数net.core.netdev_max_backlog设置。




write 数据


  1. application layer将数据copy到tcp send buffer里面,如果空间不够的话那么就会出现阻塞

  2. tcp layer等待tcp send buffer存在数据或者是需要做ack的时候,组装ip packet推送到IP layer

  3. IP layer从kernel memory申请sk_buffer,将ip data包装成为packet data,然后塞到qdisc里面。如果队列满的话那么就会出现阻塞,反馈到tcp layer阻塞

  4. NIC driver如果检测到qdisc有数据的话,调用NIC DMA Engine将packet发送出去。发送完成之后NIC向CPU发起中断释放packet data内存到Kernel Memory


send Buffer


send Buffer有关的参数如下

net.ipv4.tcp_wmem =

net.core.wmem_default

net.core.wmem_max


QDisc


QDisc(queueing discipline )位于IP层和网卡的ring buffer之间。
QDisc的队列长度由txqueuelen设置,和接收数据包的队列长度由内核参数net.core.netdev_max_backlog控制所不同,txqueuelen是和网卡关联,可以用ifconfig命令查看当前的大小(发送队列长度)


Ring Buffer


和read数据类似.




流量控制



初始状态是slow start
cwnd(congestion window) 拥塞窗口,表示一次最多发送的数据包多少。
ssthresh(slow start threshold) 慢速启动阈值。
MSS(maximum segment size) 最大分节大小,和传输网络的MTU相关。


 
天空的代码世界 更多文章 TCP的TIME_WAIT简单认识(一) 自己实现的一个chrome插件 周末随便写点东西
猜您喜欢 喜大普奔,PHP7正式发布! 精益软件开发与精益管理:从一家关闭的汽车厂重焕青春说起 ❲生涯❳你该跟你的老大聊点什么? How to become a professional iOS developer 美国科技大佬成功之前混得都有多惨