linux网络编程 ---TCP/IP协议

一、TCP/IP分层模型

在这里插入图片描述

这个网络模型究竟是干什么呢?简而言之就是进行数据封装的。

我们平常使用的程序(或者说软件)一般都是通过应用层来访问网络的,程序产生的数据会一层一层地往下传输,直到最后的网络接口层,就通过网线发送到互联网上去了。数据每往下走一层,就会被这一层的协议增加一层包装,等到发送到互联网上时,已经比原始数据多了四层包装。整个数据封装的过程就像俄罗斯套娃。

当另一台计算机接收到数据包时,会从网络接口层再一层一层往上传输,每传输一层就拆开一层包装,直到最后的应用层,就得到了最原始的数据,这才是程序要使用的数据。


给数据加包装的过程,实际上就是在数据的头部增加一个标志(一个数据块),表示数据经过了这一层,我已经处理过了。给数据拆包装的过程正好相反,就是去掉数据头部的标志,让它逐渐现出原形。


我们所说的 socket 编程,是站在传输层的基础上,所以可以使用 TCP/UDP 协议,但是不能干「访问网页」这样的事情,因为访问网页所需要的 http 协议位于应用层。

二、TCP/IP协议介绍

TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的可靠的基于字节流的通信协议,数据在传输前要建立连接,传输完毕后还要断开连接

特点

(1)TCP协议工作在传输层,对上服务socket接口,对下调用IP层
(2)TCP协议面向连接,通信前必须先3次握手建立连接关系后才能开始通信。
(3)TCP协议提供可靠传输,不怕丢包、乱序等。

TCP如何保证可靠传输

(1)TCP在传输有效信息前要求通信双方必须先握手,建立连接才能通信
(2)TCP的接收方收到数据包后会ack给发送方,若发送方未收到ack会丢包重传
(3)TCP的有效数据内容会附带校验,以防止内容在传递过程中损坏
(4)TCP会根据网络带宽来自动调节适配速率(滑动窗口技术)
(5)发送方会给各分割报文编号,接收方会校验编号,一旦顺序错误即会重传。

三次握手

TCP数据报格式
在这里插入图片描述
首部开销至少 5 * 4 = 20 个字节

带阴影的几个字段需要重点说明一下:

  1. 序号:Seq(Sequence Number)序号占32位,用来标识从计算机A发送到计算机B的数据包的序号,计算机发送数据时对此进行标记。
  2. 确认号:Ack(Acknowledge Number)确认号占32位,客户端和服务器端都可以发送,Ack = Seq + 1。
  3. 标志位:每个标志位占用1Bit,共有6个,分别为 URG、ACK、PSH、RST、SYN、FIN,具体含义如下:
    URG:紧急指针(urgent pointer)有效。
    ACK:确认序号有效。
    PSH:接收方应该尽快将这个报文交给应用层。
    RST:重置连接。
    SYN:建立一个新连接。
    FIN : 断开一个连接。

对英文字母缩写的总结:Seq 是 Sequence 的缩写,表示序列;Ack(ACK) 是 Acknowledge 的缩写,表示确认;SYN是 Synchronous 的缩写,愿意是“同步的”,这里表示建立同步连接;FIN 是 Finish 的缩写,表示完成。

连接的建立(三次握手)
在这里插入图片描述

客户端调用 socket() 函数创建套接字后,因为没有建立连接,所以套接字处于CLOSED状态;服务器端调用 listen() 函数后,套接字进入LISTEN状态,开始监听客户端请求。


这个时候,客户端开始发起请求:
(1)当客户端调用 connect() 函数后,TCP协议会组建一个数据包,并设置 SYN 标志位,表示该数据包是用来建立同步连接的。同时生成一个随机数字 1000,填充“序号(Seq)”字段,表示该数据包的序号。完成这些工作,开始向服务器端发送数据包,客户端就进入了SYN-SEND状态。


(2) 服务器端收到数据包,检测到已经设置了 SYN 标志位,就知道这是客户端发来的建立连接的“请求包”。服务器端也会组建一个数据包,并设置 SYN 和 ACK 标志位,SYN 表示该数据包用来建立连接,ACK 用来确认收到了刚才客户端发送的数据包。


服务器生成一个随机数 2000,填充“序号(Seq)”字段。2000 和客户端数据包没有关系。
服务器将客户端数据包序号(1000)加1,得到1001,并用这个数字填充“确认号(Ack)”字段。
服务器将数据包发出,进入SYN-RECV状态。


(3) 客户端收到数据包,检测到已经设置了 SYN 和 ACK 标志位,就知道这是服务器发来的“确认包”。客户端会检测“确认号(Ack)”字段,看它的值是否为 1000+1,如果是就说明连接建立成功。


接下来,客户端会继续组建数据包,并设置 ACK 标志位,表示客户端正确接收了服务器发来的“确认包”。同时,将刚才服务器发来的数据包序号(2000)加1,得到 2001,并用这个数字来填充“确认号(Ack)”字段。
客户端将数据包发出,进入ESTABLISED状态,表示连接已经成功建立。


(4) 服务器端收到数据包,检测到已经设置了 ACK 标志位,就知道这是客户端发来的“确认包”。服务器会检测“确认号(Ack)”字段,看它的值是否为 2000+1,如果是就说明连接建立成功,服务器进入ESTABLISED状态。
至此,客户端和服务器都进入了ESTABLISED状态,连接建立成功,接下来就可以收发数据了。

三次握手的关键是要确认对方收到了自己的数据包,这个目标就是通过“确认号(Ack)”字段实现的。计算机会记录下自己发送的数据包序号 Seq,待收到对方的数据包后,检测“确认号(Ack)”字段,看Ack = Seq + 1是否成立,如果成立说明对方正确收到了自己的数据包。

四次挥手

建立连接非常重要,它是数据正确传输的前提;断开连接同样重要,它让计算机释放不再使用的资源。如果连接不能正常断开,不仅会造成数据传输错误,还会导致套接字不能关闭,持续占用资源,如果并发量高,服务器压力堪忧。

过程
建立连接需要三次握手,断开连接需要四次握手,可以形象的比喻为下面的对话:
[Shake 1] 套接字A:“任务处理完毕,我希望断开连接。”
[Shake 2] 套接字B:“哦,是吗?请稍等,我准备一下。”
等待片刻后……
[Shake 3] 套接字B:“我准备好了,可以断开连接了。”
[Shake 4] 套接字A:“好的,谢谢合作。”

图解
在这里插入图片描述

建立连接后,客户端和服务器都处于ESTABLISED状态。这时,客户端发起断开连接的请求:


1) 客户端调用 close() 函数后,向服务器发送 FIN 数据包,进入FIN_WAIT_1状态。FIN 是 Finish 的缩写,表示完成任务需要断开连接。


2) 服务器收到数据包后,检测到设置了 FIN 标志位,知道要断开连接,于是向客户端发送“确认包”,进入CLOSE_WAIT状态。
注意:服务器收到请求后并不是立即断开连接,而是先向客户端发送“确认包”,告诉它我知道了,我需要准备一下才能断开连接。


3) 客户端收到“确认包”后进入FIN_WAIT_2状态,等待服务器准备完毕后再次发送数据包。


4) 等待片刻后,服务器准备完毕,可以断开连接,于是再主动向客户端发送 FIN 包,告诉它我准备好了,断开连接吧。然后进入LAST_ACK状态。


5) 客户端收到服务器的 FIN 包后,再向服务器发送 ACK 包,告诉它你断开连接吧。然后进入TIME_WAIT状态。


6) 服务器收到客户端的 ACK 包后,就断开连接,关闭套接字,进入CLOSED状态。

关于 TIME_WAIT 状态的说明

客户端最后一次发送 ACK包后进入 TIME_WAIT 状态,而不是直接进入 CLOSED 状态关闭连接,这是为什么呢?


TCP 是面向连接的传输方式,必须保证数据能够正确到达目标机器,不能丢失或出错,而网络是不稳定的,随时可能会毁坏数据,所以机器A每次向机器B发送数据包后,都要求机器B”确认“,回传ACK包,告诉机器A我收到了,这样机器A才能知道数据传送成功了。如果机器B没有回传ACK包,机器A会重新发送,直到机器B回传ACK包。
客户端最后一次向服务器回传ACK包时,有可能会因为网络问题导致服务器收不到,服务器会再次发送 FIN 包,如果这时客户端完全关闭了连接,那么服务器无论如何也收不到ACK包了,所以客户端需要等待片刻、确认对方收到ACK包后才能进入CLOSED状态。那么,要等待多久呢?
数据包在网络中是有生存时间的,超过这个时间还未到达目标主机就会被丢弃,并通知源主机。这称为报文最大生存时间(MSL,Maximum Segment Lifetime)。TIME_WAIT 要等待 2MSL 才会进入 CLOSED 状态。ACK 包到达服务器需要 MSL 时间,服务器重传 FIN 包也需要 MSL 时间,2MSL 是数据包往返的最大时间,如果 2MSL 后还未收到服务器重传的 FIN 包,就说明服务器已经收到了 ACK 包。

三、浅谈TCP/UDP

TCP 是面向连接的传输协议,建立连接时要经过三次握手,断开连接时要经过四次握手,中间传输数据时也要回复 ACK 包确认,多种机制保证了数据能够正确到达,不会丢失或出错。


UDP 是非连接的传输协议,没有建立连接和断开连接的过程,它只是简单地把数据丢到网络中,也不需要 ACK 包确认。


UDP 传输数据就好像我们邮寄包裹,邮寄前需要填好寄件人和收件人地址,之后送到快递公司即可,但包裹是否正确送达、是否损坏我们无法得知,也无法保证。UDP 协议也是如此,它只管把数据包发送到网络,然后就不管了,如果数据丢失或损坏,发送端是无法知道的,当然也不会重发。


既然如此,TCP 应该是更加优质的传输协议吧?
如果只考虑可靠性,TCP 的确比 UDP 好。但 UDP 在结构上比 TCP 更加简洁,不会发送 ACK 的应答消息,也不会给数据包分配 Seq 序号,所以 UDP 的传输效率有时会比 TCP 高出很多,编程中实现 UDP 也比 TCP 简单。


UDP 的可靠性虽然比不上TCP,但也不会像想象中那么频繁地发生数据损毁,在更加重视传输效率而非可靠性的情况下,UDP 是一种很好的选择。比如视频通信或音频通信,就非常适合采用 UDP 协议;通信时数据必须高效传输才不会产生“卡顿”现象,用户体验才更加流畅,如果丢失几个数据包,视频画面可能会出现“雪花”,音频可能会夹带一些杂音,这些都是无妨的。


与 UDP 相比,TCP 的生命在于流控制,这保证了数据传输的正确性。

最后需要说明的是:TCP 的速度无法超越 UDP,但在收发某些类型的数据时有可能接近 UDP。例如,每次交换的数据量越大,TCP 的传输速率就越接近于 UDP。

区别

TCPUDP
TCP面向连接(如打电话要先拨号建立连接)UDP是无连接的,即发送数据之前不需要建立连接
TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达UDP尽最大努力交付,即不保 证可靠交付
TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流UDP是面向报文的
每一条TCP连接只能是点到点的UDP支持一对一,一对多,多对一和多对多的交互通信
TCP首部开销20字节UDP的首部开销小,只有8个字节
TCP的逻辑通信信道是全双工的可靠信道UDP则是不可靠信道
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值