网络编程必备:深入理解TCP/IP协议栈(含posix API实现)(上)

本文涉及的产品
数据传输服务 DTS,数据迁移 small 3个月
推荐场景:
MySQL数据库上云
简介: 网络编程必备:深入理解TCP/IP协议栈(含posix API实现)

前言:TCP/IP协议并不是单纯的俩个协议,而是一个很大的协议栈的总称。TCP/IP 协议栈是构成网络通信的核心骨架,它定义了电子设备如何连入因特网,以及数据如何在它们之间进行传输。TCP/IP 协议采用4层结构,分别是应用层、传输层、网络层和链路层,每一层都呼叫它的下一层所提供的协议来完成自己的需求。下面我们来看TCP/IP的四层结构。网络协议有OSI七层协议和TCP/IP四层协议,还有一个五层协议,其实四层协议可以看做是七层协议的简化版。

一、TCP/IP整体概念

1.1物理介质

物理介质就是把电脑连接起来的物理手段,常见的有光纤、双绞线,以及无线电波,它决定了电信号(0和1)的传输方式,物理介质的不同决定了电信号的传输带宽、速率、传输距离以及抗干扰性等等。TCP/IP协议栈分为四层,每一层都由特定的协议与对方进行通信,而协议之间的通信最终都要转化为 0 和 1 的电信号,通过物理介质进行传输才能到达对方的电脑,因此物理介质是网络通信的基石。

下面我们先通过一张图先来大概了解一下TCP/IP协议的基本框架以及数据的处理流程:


当通过http发起一个请求时,应用层、传输层、网络层和链路层的相关协议依次对该请求进行包装并携带对应的首部,最终在链路层生成以太网数据包,以太网数据包通过物理介质传输给对方主机,对方接收到数据包以后,然后再一层一层采用对应的协议进行拆包,最后把应用层数据交给应用程序处理。

网络通信就好比送快递,商品外面的一层层包裹就是各种协议,协议包含了商品信息、收货地址、收件人、联系方式等,然后还需要配送车、配送站、快递员,商品才能最终到达用户手中。

一般情况下,快递是不能直达的,需要先转发到对应的配送站,然后由配送站再进行派件。

配送车就是物理介质,配送站就是网关, 快递员就是路由器,收货地址就是IP地址,联系方式就是MAC地址。

快递员负责把包裹转发到各个配送站,配送站根据收获地址里的省市区,确认是否需要继续转发到其他配送站,当包裹到达了目标配送站以后,配送站再根据联系方式找到收件人进行派件。

1.2链路层

网络通信就是把有特定意义的数据通过物理介质传送给对方,单纯的发送 0 和 1 是没有意义的,要传输有意义的数据,就需要以字节为单位对 0 和 1 进行分组,并且要标识好每一组电信号的信息特征,然后按照分组的顺序依次发送。以太网规定一组电信号就是一个数据包,一个数据包被称为一帧, 制定这个规则的协议就是以太网协议。

以太网规协议定,接入网络的设备都必须安装网络适配器,即网卡, 数据包必须是从一块网卡传送到另一块网卡。而网卡地址就是数据包的发送地址和接收地址,也就是帧首部所包含的MAC地址,MAC地址是每块网卡的身份标识,就如同我们身份证上的身份证号码,具有全球唯一性。

有了MAC地址以后,以太网采用广播形式,把数据包发给该子网内所有主机,子网内每台主机在接收到这个包以后,都会读取首部里的目标MAC地址,然后和自己的MAC地址进行对比,如果相同就做下一步处理,如果不同,就丢弃这个包。

所以链路层的主要工作就是对电信号进行分组并形成具有特定意义的数据帧,然后以广播的形式通过物理介质发送给接收方。

1.3网络层

对于上面的过程,肯定会产生下面几个疑问:

1.发送者如何知道接收者的MAC地址?
2.发送者如何知道接收者和自己同属一个子网?
3.如果接收者和自己不在同一个子网,数据包如何发给对方?

为了解决这些问题,网络层引入了三个协议,分别是IP协议、ARP协议、路由协议。IP协议制定了IP地址来判断俩个主机是否属于同一个子网。ARP协议根据IP地址获取MAC地址。路由协议根据信道情况,选择并设定路由,以最佳路径来转发数据包。

所以,网络层的主要工作是定义网络地址,区分网段,子网内MAC寻址,对于不同子网的数据包进行路由。

1.4传输层

链路层定义了主机的身份,即MAC地址, 而网络层定义了IP地址,明确了主机所在的网段,有了这两个地址,数据包就从可以从一个主机发送到另一台主机。但实际上数据包是从一个主机的某个应用程序发出,然后由对方主机的应用程序(进程)接收。而每台电脑都有可能同时运行着很多个应用程序(进程),所以当数据包被发送到主机上以后,是无法确定哪个应用程序(进程)要接收这个包。传输层提供了进程间的逻辑通信,传输层向高层用户屏蔽了下面网络层的核心细节,使应用程序看起来像是在两个传输层实体之间有一条端到端的逻辑通信信道。

1.5应用层

理论上讲,有了以上三层协议的支持,数据已经可以从一个主机上的应用程序传输到另一台主机的应用程序了,但此时传过来的数据是字节流,不能很好的被程序识别,操作性差。因此,应用层定义了各种各样的协议来规范数据格式,常见的有 HTTP、FTP、SMTP 等。

1.6四层协议整体流程

链路层:对0和1进行分组,定义数据帧,确认主机的物理地址,传输数据;网络层:定义IP地址,确认主机所在的网络位置,并通过IP进行MAC寻址,对外网数据包进行路由转发;传输层:定义端口,确认主机上应用程序的身份,并将数据包交给对应的应用程序;应用层:定义数据格式,并按照对应的格式解读数据。

用一句话来概括就是:当你输入一个网址并按下回车键的时候,首先,应用层协议对该请求包做了格式定义;紧接着传输层协议加上了双方的端口号,确认了双方通信的应用程序;然后网络协议加上了双方的IP地址,确认了双方的网络位置;最后链路层协议加上了双方的MAC地址,确认了双方的物理位置,同时将数据进行分组,形成数据帧,采用广播方式,通过传输介质发送给对方主机。而对于不同网段,该数据包首先会转发给网关路由器,经过多次转发后,最终被发送到目标主机。目标机接收到数据包后,采用对应的协议,对帧数据进行组装,然后再通过一层一层的协议进行解析,最终被应用层的协议解析并交给服务器处理。

二、传输层

传输层(Transport Layer)是ISO OSI协议的第四层协议,实现端到端的数据传输。该层是两台计算机经过网络进行数据通信时,第一个端到端的层次,具有缓冲作用。当网络层服务质量不能满足要求时,它将服务加以提高,以满足高层的要求;当网络层服务质量较好时,它只用很少的工作。传输层还可进行复用,即在一个网络连接上创建多个逻辑连接。

传输层在终端用户之间提供透明的数据传输,向上层提供可靠的数据传输服务。传输层在给定的链路上通过流量控、分段/重组和差错控制。一些协议是面向链接的。这就意味着传输层能保持对分段的跟踪,并且重传那些失败的分段。


传输层作用

  • 传输层实现应用进程间的端到端(end-to-end)通信
  • 向应用层提供通信服务

多路分解与复用

  • 多路复用:所有应用进程的数据通过传输层传输到IP层;
  • 多路分解:传输层收到的数据交付给相应的应用进程。

2.1用户数据报协议UDP

端到端的、尽力而为的、无连接的数据报传输服务 1.无连接的 2.尽最大努力交付,即不保证可靠交付 3.面向报文的(在IP的功能上简单扩展了端到端) 4.没有拥塞控制 5.支持一对一、一对多、多对一和多对多的交互通信(需要组播的通信都是建立在UDP之上)

2.2传输控制协议TCP

端到端的、可靠的、面向连接的字节流服务 a).面向连接:先建立逻辑连接,进行双向数据流传输,通信结束后撤销连接 b).面向字节流 c).点对点的全双工通信 d).可靠传输:对一个连接上传输的每个字节编号,通过接收确认和重传来保证可靠传输 c).流量控制:防止发送方发出的数据超出接收方的接收能力。

多路复用:源、目的端口 连接管理:序号、确认号、SYN、FIN 可靠传输:序号、确认号 流量控制:接收窗口 拥塞控制:未在TCP首部中体现(序号、确认号、接收窗口)。

2.3连接管理

  • 每条TCP连接是一对点到点的字节流
  • 每条TCP连接者两个端点,即套接字(sokect)={IP : port}
  • 每条TCP连接由两个端点唯一标识,TCP连接={socket1, socket2} = {{IP1 : port1}, {IP2 : port2}}
  • TCP连接有3个阶段:连接建立、数据传输、连接释放

1)TCP连接建立的目的

①使通信双方确知对方的存在  ②双方确定自己的初始序列号,并通知对方  ③允许双方协商一些参数(最大报文长度、窗口大小等)  ④对传输实体资源进行分配

2)TCP连接建立的方式

采用客户端服务器方式(C/S),主动发起连接建立的应用进程叫做客户端,被动等待连接建立的叫服务器端。

3)连接建立(三次握手)

①服务器进程B被动打开连接,进入LISTEN(收听)状态,等待客户端发出请求  ②客户进程A主动打开连接,向B发送连接请求报文段(报文段不挟带数据),SYN=1,序号=x,进入SYN-SENT(同步已发送)状态  ③服务器进程B收到请求后,向A发送确认报文段(报文段不挟带数据),SYN=1,ACK=1,确认号=x+1,序号=y,进入SYN-RCVD(同步收到)状态  ④客户进程A收到确认后,向B发送确认报文段(报文段可以携带数据,不携带数据时不消耗序号,下一个序号依然是x+1),ACK=1,确认号=y+1,序号=x+1,进入ESTABLISHED(已建立连接)状态,B收到确认后,也进入ESTABLISHED状态


为什么A需要向B发送最后一个确认报文段:为了防止“已失效的连接请求报文段”突然又传到B发生错误,以至于B一直等待A发送数据,B的资源被浪费。

4)连接释放(四次挥手)

①A,B都处于ESTABLISHED状态; ②客户进程A主动关闭连接,向B发送连接释放请求报文段(报文段不挟带数据),FIN=1,序列号=u,进入FIN-WAIT-1(终止等待1)状态; ③B收到A的连接释放报文段后,应答确认,ACK=1,确认号=u+1,序号=v,进入CLOSE-WAIT (关闭等待)状态,B仍然可以向A发送数据,A进入FIN-WAIT-2(终止等待2)状态; ④若B已经没有向A的数据,其应用进程通知TCP连接释放,B向A发送连接释放报文段,FIN=1,ACK=1,确认号=u+1,序号=w,进入LAST-ACK(最后确认)状态; ⑤A收到B的链接释放报文段后,应答确认,ACK=1,确认号=w+1,序号=u+1,进入TIME-TIME-WAIT(时间等待)状态,B收到A的确认后,进入CLOSED状态

A必须经过时间等待计时器设置的时间2MSL(默认2分钟)后,进入CLOSED状态:确保A发送的最后一个ACK报文段能够到达B;防止“已失效的连接请求报文段”出现在本连接中。

【文章福利】小编推荐自己的Linux C++技术交流群:【1106675687】整理了一些个人觉得比较好的学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!!!

资料领取直通车:https://docs.qq.com/doc/DTlhVekRrZUdDUEpy Linux服务器学习网站:https://ke.qq.com/course/417774?flowToken=1028592

可靠传输

  • 发送方的TCP:维护一个发送缓冲区
  • 维护3个指针:LastByteAcked、LastByteSent、LastByteWritten
  • 发送窗口=min(通知窗口,拥塞窗口)
  • 累积确认(Cumulative ACK) :对按序到达的最后一个报文段进行确认
  • 选择确认(Selective ACK) :确认接收到的不连续的数据块的边界(使用首部的SACK选项,不影响确认号字段的使用)

流量控制

目的:为了防止发送方给慢接收方发数据造成接受崩溃,缓冲区溢出 原理:接收方通知发送方自己的接受窗口大小,发送方的发送窗口≤接收方的接受窗口

问题:B向A发送了零窗口报文段后,B的接受缓存有了一些存储空间,于是B向A发送了rwnd=400的报文段,然而报文段在传送过程中丢失,这样A一直等待B发送的非零窗口通知,B一直等待A发送数据,从而形成死锁局面。

解决:TCP为每一个连接设置一个持续计时器,只要TCP链接一方收到零窗口通知,就启动持续计时器,计时器到期,发送零窗口探测报文段,而对方就在确认这个探测报文段时给出现在的窗口值,①如果窗口仍然是零,那么重新设置持续计时器;②否则死锁的僵局就可以打破。

2.4自适应重传

1)超时重传

报文段的往返时间:RTT 加权平均往返时间:RTTS RTT的偏差加权平均值:RTTD 超时重传时间:RTO RTTS = (1 - α) * RTTS + α * 新的RTT样本值 (α一般为1/8) RTTD = (1 - β) * RTTD + β * | RTTS - 新的RTT样本值 | (β一般为1/4) RTO = RTTS + 4 * RTTD

Karn算法:①每次超时重传一个报文段时,停止计算新RTT样本值 ②每次超时重传一个报文段时,就把超时重传时间RTO增大y倍(一般为2倍) ③当不发生报文段重传时,才计算RTTS和超时重传时间RTO

2)快速重传

原因:超时重传作为TCP最基本的重传机制,效率较低。

超时的粗粒度实现方法导致连接在等待一个定时器超时时,很长一段时间连接无效。

基本思想:①接收方:当报文段到达,立刻回复ACK,即使该序号已被确认过 ②发送方:收到一个重复ACK(同一个确认的再一次重传称为重复确认),就知道接收方必定收到乱序到达的报文段,表明其前面的分组可能丢失。收到3个重复ACK时,立刻触发重传。

2.5拥塞控制

1)窗口大小

MaxWindow = min (cwnd, AdvertisedWindow) 拥塞窗口cwnd (Congestion Windows):拥塞控制算法决定,可以同时发出的最大字节数以防止造成网络拥塞 通知窗口 (AdvertisedWindow):接收方决定,可以同时发出的最大字节数以防止超出接收方的接收能力。

2)拥塞控制算法

①慢启动 把初始拥塞窗口 cwnd 设置为不超过2至4个SMSS(最大报文段长度),在每收到一个对新的报文段的确认后,把cwnd增加1个 SMSS 的数值数(每经过一个传输轮次,cwnd就加倍) 设置一个慢开始门限ssthresh 当cwnd < ssthresh时,使用慢开始算法 当cwnd ≥ ssthresh时,使用拥塞避免算法。

②拥塞避免(加法增大):每经过一个往返时间RTT把发送方的cwnd加1,使得cwnd慢性增加 ③快重传(乘法减小):收到3个重复ACK立即触发重传 ④快恢复(在快重传之后)

  1. ssthresh减小为当前cwnd的一半:ssthresh = cwnd / 2
  2. 新拥塞窗口 cwnd = 新的 ssthresh
  3. 执行拥塞避免 (AIMD),使cwnd缓慢线性增大

三、应用层

3.1概念

5层因特网协议栈:应用层 -> 传输层 -> 网络层 -> 数据链路层 -> 物理层

7层OSI参考模型:应用层 ->表示层 -> 会话层 -> 传输层 -> 网络层 -> 数据链路层 -> 物理层

为什么我们要在计算机网络中分层次?

因为如果两台计算机能够相互通信的话,实际实现起来是非常困难操作的。我们分层的目的就是为了将困难的问题简单化,并且如果我们分层了,我们在使用的时候就可以仅仅关注我们需要关注的层次,而不用理会其他层

如果需要改动设计的时候,我们只需要把变动的层替换即可,并不用涉及到其他的层次。这与我们程序设计中的低耦合是一个概念。

每层作用如下:

  • 物理层:通过媒介传输比特,确定机械及电气规范(比特Bit),通过电频的高低来传输0和1这样的电信号
  • 数据链路层:将比特组装成帧和点到点的传递(帧Frame),将无规则的0和一同通过一套规则来分组传输,于是出现了以太网协议。以太网协议规定:一组电信号构成一个数据包,这个数据包称为帧,每一个帧由标头(Head)和数据(Data)两部分组成,标头部分的大小为18字节
  • 网络层:负责数据包从源到宿的传递和网际互连(包PackeT)
  • 传输层:提供端到端的可靠报文传递和错误恢复(段Segment)
  • 会话层:建立、管理和终止会话(会话协议数据单元SPDU)
  • 表示层:对数据进行翻译、加密和压缩(表示协议数据单元PPDU)
  • 应用层:允许访问OSI环境的手段(应用协议数据单元APDU)

每一层的协议如下:

  • 物理层:RJ45、CLOCK、IEEE802.3 (中继器,集线器,网关)
  • 数据链路:PPP、FR、HDLC、VLAN、MAC (网桥,交换机)
  • 网络层:IP、ICMP、ARP、RARP、OSPF、IPX、RIP、IGRP、 (路由器)
  • 传输层:TCP、UDP、SPX
  • 会话层:NFS、SQL、NETBIOS、RPC
  • 表示层:JPEG、MPEG、ASII
  • 应用层:FTP、DNS、Telnet、SMTP、HTTP、WWW、NFS

3.2DNS域名系统

NS(Domain Name System)提供了什么服务?

  • 一个由分层的DNS服务器(DNS Server)实现的分布式数据库
  • 使得主机能够查询分布式数据库的应用协议
  • DNS协议是运行在UDP之上,用53号端口

分布式、层次数据库:

  • 根DNS服务器:全球有四百多个根DNS服务器,由13个不同的组织管理,根服务器提供TLD服务器的IP地址。
  • 顶级域(TLD)DNS服务器:顶级域(如:com、org、net和org)和所有的国家顶级域(uk、fr、cn、jp)都有TLD服务器。TLD服务器提供了权威DNS服务器的IP地址
  • 权威DNS服务器:再因特网上具有公共可访问的主机(就是你的服务器主机地址),权威DNS服务器将主机名映射为IP地址
  • 本地DNS服务器:不属于DNS服务器的层次结构,但是也是必不可少的。当我们发出DNS请求时,该请求先被发送到本地DNS服务器,它起着代理的作用

域名解析过程:

假设我们(主机是http://a.xyz.com)获取http://www.baidu.com的IP地址,同时本地DNS服务器为http://dns.xyz.com。首先我们的主机向本地DNS服务器发送一个DNS查询报文(报文包含被查询的主机名),然后本地DNS服务器将该报文转发到根DNS服务器,根DNS服务器发现了com前缀,然后向本地DNS服务器返回com的顶级域(TLD)DNS服务器的IP地址列表。本地DNS服务区再向这些TLD服务器发送查询报文,TLD服务器注意到了http://baidu.com前缀,然后将负责http://www.baidu.com的权威DNS服务器的IP地址返回给本地DNS服务器,最后,本地DNS服务器向该IP地址进行发送报文查询,权威DNS服务器返回了http://www.baidu.com的IP地址给本地DNS服务器,本地DNS服务器再将该DNS发送到我们主机,我们开始访问该IP地址。

递归查询过程如下:

迭代查询过程如下:

理论上来讲,任何DNS查询既可以是递归也可以是迭代的。在实践中,查询通常是从请求主机到本地DNS服务器的查询时递归的,其余查询时迭代的

  • 主机向本地域名服务器的查询一般都是采用递归查询:如果主机所询问的本地域名服务器不知道被查询域名的 IP 地址,那么本地域名服务器就以 DNS 客户的身份,向其他根域名服务器继续发出查询请求报文。
  • 本地域名服务器向根域名服务器的查询通常是采用迭代查询:当根域名服务器收到本地域名服务器的迭代查询请求报文时,要么给出所要查询的 IP 地址,要么告诉本地域名服务器:“你下一步应当向哪一个域名服务器进行查询”。然后让本地域名服务器进行后续的查询。
相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
云原生实践公开课
课程大纲 开篇:如何学习并实践云原生技术 基础篇: 5 步上手 Kubernetes 进阶篇:生产环境下的 K8s 实践 相关的阿里云产品:容器服务&nbsp;ACK 容器服务&nbsp;Kubernetes&nbsp;版(简称&nbsp;ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情:&nbsp;https://www.aliyun.com/product/kubernetes
相关文章
|
2天前
|
网络协议 网络架构
TCP IP协议簇:网络通信的基石
【4月更文挑战第20天】
21 6
|
1月前
|
移动开发 网络协议 安全
网络面试题:什么是 TCP/IP?
网络面试题:什么是 TCP/IP?
43 0
网络面试题:什么是 TCP/IP?
|
1月前
|
数据可视化 Linux API
如何在Linux使用docker部署Swagger Editor并实现无公网IP远程协同编辑API文档
如何在Linux使用docker部署Swagger Editor并实现无公网IP远程协同编辑API文档
|
2月前
|
JSON 缓存 运维
Dataphin数据服务API开启IP白名单调用鉴权
Dataphin数据服务API提供便捷的API开发及运维、应用调用权限管理等功能,为数据业务化提供了坚实的支撑。在应用调用API的时候,Dataphin可支持通过AcessKey方式的调用鉴权。而在企业内部网络中,也可以使用IP白名单方式简化调用。本文将为您介绍如何开启IP白名单的调用鉴权。
|
2月前
|
网络协议 网络性能优化 Python
在Python中进行TCP/IP网络编程
在Python中进行TCP/IP网络编程
34 6
|
8天前
|
API Go
使用Go语言通过API获取代理IP并使用获取到的代理IP
使用Go语言通过API获取代理IP并使用获取到的代理IP
|
9天前
|
安全 Java API
java借助代理ip,解决访问api频繁导致ip被禁的问题
java借助代理ip,解决访问api频繁导致ip被禁的问题
|
11天前
|
网络协议 Java API
深度剖析:Java网络编程中的TCP/IP与HTTP协议实践
【4月更文挑战第17天】Java网络编程重在TCP/IP和HTTP协议的应用。TCP提供可靠数据传输,通过Socket和ServerSocket实现;HTTP用于Web服务,常借助HttpURLConnection或Apache HttpClient。两者结合,构成网络服务基础。Java有多种高级API和框架(如Netty、Spring Boot)简化开发,助力高效、高并发的网络通信。
|
19天前
|
网络协议 Linux SDN
虚拟网络设备与Linux网络协议栈
在现代计算环境中,虚拟网络设备在实现灵活的网络配置和隔离方面发挥了至关重要的作用🔧,特别是在容器化和虚拟化技术广泛应用的今天🌐。而Linux网络协议栈则是操作系统处理网络通信的核心💻,它支持广泛的协议和网络服务🌍,确保数据正确地在网络中传输。本文将深入分析虚拟网络设备与Linux网络协议栈的关联,揭示它们如何共同工作以支持复杂的网络需求。
|
1月前
|
域名解析 缓存 网络协议
网络原理-TCP/IP(7)
网络原理-TCP/IP(7)