【linux】系统编程-7-网络编程


前言

10. 网络编程

  • 互联网通信所要遵守的众多协议,被统称为TCP/IP。

10.1 简要网络知识

  • TCP/IP是一个庞大的协议族,它是众多网络协议的集合,包括:ARP、IP、ICMP、UDP、TCP、DNS、DHCP、HTTP、FTP、MQTT等等
  • 分层
graph LR A[应用层] --> a[DNS HTTP FTP SMTP MQTT邮件协议] B[传输层] --> b[主要是TCP UDP] C[网络层] --> c[主要为IP ICM ARP协议] D[链路层] --> d[MAC层] E[物理层] --> e[主要定义物理传输介质]
  • 参考图

10.2 IP协议

  • IP协议(Internet Protocol),又称之为网际协议,IP协议处于IP层工作,它是整个TCP/IP协议栈的核心协议

10.2.1 IP地址编址

  • 参考图
类别 第一字节(二进制) 第一字节取值范围 网络号个数 主机号个数 适用范围
A类 0XXX XXXX 0-127 125 16777214 大型网络
B类 10XX XXXX 128-191 16368 65534 中型网络
C类 110X XXXX 192-223 209715 254 小型网络
D类 1110 XXXX 224-239 - - 多播
E类 1111 XXXX 240-255 - - 保留

10.2.2 特殊IP地址

10.2.1 首限广播地址
  • 受限广播地址用于定义整个互联网,如果设备想使IP数据报被整个网络所接收,就发送这个目的地址全为1的广播包,但这样会给整个互联网带来灾难性的负担,所以在任何情况下,路由器都会禁止转发目的地址为255.255.255.255的广播数据包,因此这样的数据包仅会出现在本地网络中(局域网),255.255.255.255这个地址指本网段内的所有主机, 相当于“房子里面的人都听着”通知所有主机。
  • 其实就是对整个IP生效,即网络号+主机号都全为1,对整个互联网生效
10.2.2 直接广播地址
  • 直接广播地址仅是主机号为1,广播地址代表本网络内的所有主机。
  • 其实就是对整个IP生效,即主机号都全为1,对同一网络号内的所有主机生效
10.2.3 多播地址
  • 多播地址用在一对多的通信中,属于分类编址中的D类地址, D类地址只能用作目的地址,而不能作为主机中的源地址。
10.2.4 回环地址
  • 127网段的所有地址都称为环回地址,主要用来测试网络协议是否工作正常的作用。比如在电脑中使用ping 命令去ping 127.1.1.1就可以测试本地TCP/IP协议是否正常。用通俗的话表示,就是“我自己”,不能以127网段中的IP地址作为主机地址,因此A类地址又少了一个可用网络号。
10.2.5 本网络本主机
  • IP地址32bit全为0的地址(0.0.0.0)表示的是本网络本主机,这个IP地址在IP数据报中只能用作源IP地址,这发生在当设备启动时但又不知道自己的IP地址情况下。
  • 在使用DHCP分配IP地址的网络环境中,这样的地址是很常见的,主机为了获得一个可用的IP地址,就给DHCP服务器发送IP数据报,并用这样的地址(0.0.0.0)作为源地址,目的地址为255.255.255.255(因为主机这时还不知道DHCP服务器的IP地址),然后DHCP服务器就会知道这个主机暂时没有IP地址,那么就会分配一个IP给这个主机。

10.3 UDP协议

  • UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议
  • 特点
    • 无连接,即通信时不需要创建连接(发送数据结束时也没有连接可以释放)所以减小了开销和发送数据前的时延;
    • 不可靠,最大努力交付,不保证可靠交付,因此主机不需要维护复杂的连接状态;
    • 面向报文,只在应用层交下来的报文前增加了首部后就向下交付IP层;
    • 无流量控制和无阻塞控制,即使网络中存在阻塞,也不会影响发送端的发送频率;
    • 支持一对一、一对多、多对一、多对多的交互通信;
    • 首部开销小,只有8个字节,它比TCP的20个字节的首部要短;
    • 速度快,UDP没有TCP的握手、确认、窗口、重传、拥塞控制等机制,UDP是一个无状态的传输协议,所以它在传递数据时非常快,即使在网络拥塞的时候UDP也不会降低发送的数据。
  • 应用环境
    • 常用于实时视频的传输,比如直播、网络电话等,因为即使是出现了数据丢失的情况,导致视频卡帧,是可以容忍的

10.4 TCP协议

  • TCP是提供一种面向连接、可靠的字节流传输服务
  • 与UDP的区别
    • TCP面向连接、数据可靠。
    • UDP运载的数据是以报文的形式,各个报文在网络中互不相干传输,到达目标主机的顺序是不一样的,所以需要在应用层进行重装。
    • TCP采用数据流的形式传输,TCP协议会给每个传输的字节进行编号,在传输的过程中,发送方把数据的起始编号与长度放在TCP报文中,在接收方将所有数据按照编号组装起来,然后返回一个确认,当所有数据接收完成后才将数据递交到应用层中。
  • TCP的特性
    • 连接机制:TCP是一个面向连接的协议
    • 确认与重传:一个完整的TCP传输必须有数据的交互。发送方发送数据后必须等待接收方的结果反馈,并开启定时器,超时未接收到数据则认为发送失败,进行重发操作;接收方接收到数据后必须向发送方反馈结果。
    • 缓冲机制
      • 发送方:应用程序的数据大小、类型都是不可预估的。在数据量很小时,TCP会将数据存储在一个缓冲空间中,等到数据量足够大的时候进行发送数据,直至确认接收方正确接收成功才删除。
      • 接收方:由于网络中传输的数据报到达接收方的时间是不一样的,所以需要存起来进行重装再交给应用层。
    • 全双工通信:TCP是全双工通信。双方都是主机,任意一方都可以断开链接。
    • 流量控制
      • 流量控制是一个速度匹配服务,即发送方的发送速率与接收方应用程序的读取速率相匹配。
      • TCP通过让发送方维护一个称为接收窗口(receive window)的变量来提供流量控制。
      • 接收窗口(rwnd),接收方会将此窗口值放在 TCP 报文的首部中的窗口字段,然后传递给发送方,这个窗口的大小是在发送数据的时候动态调整的。
      • 若发送方收到的窗口值为0,此时发送方还是会进行发送只有一个字节的报文段。
    • 差错控制:TCP协议采用校验和的方式来检验数据有效性。同时,接收方也会把接收到的数据报进行整理,重装。
    • 拥塞控制:在网络中拥塞的情况下调整自身的发送速度,这种形式对发送方的控制被称为拥塞控制(congestion control),采取的措施是限制发送方的发送速度。

10.5 端口号的概念

  • TCP连接是两个不同主机的应用连接,而传输层与上层协议是通过端口号进行识别的。
  • 端口号的取值范围为:0~65535,不同端口号对应上层应用的不同线程
  • 一台主机可能只有一个IP地址,但是可以有多个端口号
  • 通过 IP地址+端口号 来区分主机不同的线程。
  • 常见的TCP协议端口号有21、53、80等等
端口号 协议 说明
20/21 FTP 文件传输协议,使得主机间可以共享文件。
23 Telnet 终端远程登录,它为用户提供了在本地计算机上完成远程主机工作的能力。
25 SMTP 简单邮件传输协议,它帮助每台计算机在发送或中转信件时找到下一个目的地。
69 TFTP 普通文件传输协议。
80 HTTP 超文本传输协议,通过使用网页浏览器、网络爬虫或者其它的工具,客户端发起一个HTTP请求到服务器上指定端口(默认端口为80),应答的服务器上存储着一些资源,比如HTML文件和图像,那么就会返回这些数据到客户端。
110 POP3 邮局协议版本3,本协议主要用于支持使用客户端远程管理在服务器上的电子邮件。

10.6 TCP报文段

  • TCP报文段由 首部 + 数据域 组成

10.7 TCP建立连接

  • TCP是一个面向连接的协议,连接俗称握手。
  • 三次握手建立连接
    • 建立连接的过程是由客户端发起,服务端等待客户请求
    • 第一步:客户端向服务器端发送一个SYN报文段(只有首部,且SYN被置 1),初始序号(ISN)随机选择,假设为A,ACK置 0。
    • 第二步:服务器端收到SYN报文段,便知道客户端需要请求握手,从SYN报文段中提取对应的信息,为该TCP连接分配TCP缓存和变量,并向该客户TCP发送允许连接的报文段(握手应答报文)。这个报文段只有首部,包含3个重要的信息:(建立客户端-->服务端的连接
      1. SYN与ACK标志位1
      2. 将TCP报文段首部的确认序号字段设置为A+1(这个A(ISN)是从握手请求报文中得到)。
      3. 服务器随机选择自己的初始序号(ISN,注意此ISN是服务器端的ISN,假设为B),并将其放置到TCP报文段首部的序号字段中。
    • 第三步:客户端接收到服务器端的握手应答后,会将SYN置 0,ACK置 1,确认序号置为 B+1, 设置窗口值,可以添加数据域的报文段发给服务器端。同时给该TCP连接分配缓存和变量。(建立服务端-->客户端的连接
  • 参考图:

10.8 TCP终止连接

  • 建立连接需要三次握手,而终止连接需要四次挥手。
  • 四次挥手终止连接
    • 第一步:客户端发出FIN报文段(首部FIN被置 1),序号假设为C,ACK被置 1,但是确认序号是无效的。
    • 第二步:当服务器端收到FIN报文段,它返回一个ACK报文段(终止连接应答),确认序号为C+1。此时断开客户端-->服务器端的方向
    • 第三步:服务器端发出FIN报文段向客户端请求终止连接,此时序号为D,ACK被置 1,但是确认序号是无效的。
    • 第四步:当客户端收到FIN报文段,它返回一个ACK报文段(终止连接应答),确认序号为D+1。此时断开服务器端-->客户端的连接
  • 参考图

10.9 TCP状态

  • TCP协议的状态如下:
    • CLOSED:初始状态,表示TCP连接是“关闭着的”或“未打开的”。
    • LISTEN :表示服务器端的某个SOCKET处于监听状态,可以接受客户端的连接。
    • SYN_RCVD :表示服务器接收到了来自客户端请求连接的SYN报文。在正常情况下,这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态,很短暂,基本上用netstat很难看到这种状态,除非故意写一个监测程序,将三次TCP握手过程中最后一个ACK报文不予发送。当TCP连接处于此状态时,再收到客户端的ACK报文,它就会进入到ESTABLISHED状态。
    • SYN_SENT :这个状态与SYN_RCVD状态相呼应,当客户端SOCKET执行connect()进行连接时,它首先发送SYN报文,然后随即进入到SYN_SENT 状态,并等待服务端的发送三次握手中的第2个报文。SYN_SENT状态表示客户端已发送SYN报文。
    • ESTABLISHED :表示TCP连接已经成功建立。
    • FIN_WAIT_1 :这个状态得好好解释一下,其实FIN_WAIT_1FIN_WAIT_2两种状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:FIN_WAIT_1状态实际上是当SOCKETESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET进入到FIN_WAIT_1状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2状态。当然在实际的正常情况下,无论对方处于任何种情况下,都应该马上回应ACK报文,所以FIN_WAIT_1状态一般是比较难见到的,而FIN_WAIT_2状态有时仍可以用netstat看到。
    • FIN_WAIT_2 :上面已经解释了这种状态的由来,实际上FIN_WAIT_2状态下的SOCKET表示半连接,即有一方调用close()主动要求关闭连接。注意:FIN_WAIT_2是没有超时的(不像TIME_WAIT状态),这种状态下如果对方不关闭(不配合完成4次挥手过程),那这个 FIN_WAIT_2 状态将一直保持到系统重启,越来越多的FIN_WAIT_2状态会导致内核crash
    • TIME_WAIT :表示收到了对方的FIN报文,并发送出了ACK报文。 TIME_WAIT状态下的TCP连接会等待2*MSL(Max Segment Lifetime,最大分段生存期,指一个TCP报文在Internet上的最长生存时间。每个具体的TCP协议实现都必须选择一个确定的MSL值,RFC 1122建议是2分钟,但BSD传统实现采用了30秒,Linux可以在cat/proc/sys/net/ipv4/tcp_fin_timeout看到本机的这个值),然后即可回到CLOSED可用状态了。如果FIN_WAIT_1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。(这种情况应该就是四次挥手变成三次挥手的那种情况)
    • CLOSING :这种状态在实际情况中应该很少见,属于一种比较罕见的例外状态。正常情况下,当一方发送FIN报文后,按理来说是应该先收到(或同时收到)对方的ACK报文,再收到对方的FIN报文。但是CLOSING状态表示一方发送FIN报文后,并没有收到对方的ACK报文,反而却也收到了对方的FIN报文。什么情况下会出现此种情况呢?那就是当双方几乎在同时close()一个SOCKET的话,就出现了双方同时发送FIN报文的情况,这是就会出现CLOSING状态,表示双方都正在关闭SOCKET连接。
    • CLOSE_WAIT :表示正在等待关闭。怎么理解呢?当对方close()一个SOCKET后发送FIN报文给自己,你的系统毫无疑问地将会回应一个ACK报文给对方,此时TCP连接则进入到CLOSE_WAIT状态。接下来呢,你需要检查自己是否还有数据要发送给对方,如果没有的话,那你也就可以close()这个SOCKET并发送FIN报文给对方,即关闭自己到对方这个方向的连接。有数据的话则看程序的策略,继续发送或丢弃。简单地说,当你处于CLOSE_WAIT状态下,需要完成的事情是等待你去关闭连接。
    • LAST_ACK :当被动关闭的一方在发送FIN报文后,等待对方的ACK报文的时候,就处于LAST_ACK状态。当收到对方的ACK报文后,也就可以进入到CLOSED可用状态了。

参考

* 野火
posted @ 2021-01-20 18:47  李柱明  阅读(268)  评论(0编辑  收藏  举报