计算机网络4

一、网络分层

1、为什么要网络分层?

复杂的程序都要分层,这是程序设计的要求。

2、程序是如何工作的?

浏览器—发起HTTP请求—使用端口号发给程序—调用函数HTTP正文加TCP头,记录下源端口号和目的端口号—调用函数加IP头,记录下源IP地址和目标IP地址—调用函数加MAC头,记录下源MAC地址和目标MAC地址—内容完整,网口发送程序包—网口接收程序包,程序处理—调用函数,摘掉MAC头发现目标MAC地址相符—调用函数摘掉IP头—IP地址相符(IP地址不符,转发出去)—地址是TCP的,调用函数,摘掉TCP头—根据端口号选择发送给监听的不同应用

3、层与层之间的关系

所有不能表示出层层封装含义的比喻都是不恰当的。

只要是在网络上跑的包,都是完整的。可以有下层没上层,绝对不可能有上层没下层。

二层设备:收进去的是整个HTTP包,只把MAC头摘下来,看看是丢弃还是转发还是保留

三层设备:把MAC头摘下来之后,再把IP头摘下来,看看是丢弃还是转发还是保留

二、UDP协议

1、TCP 和 UDP区别

建立连接,是为了在客户端和服务端维护连接,而建立一定的数据结构来维护双方交互的状态,用这样的数据结构来保证所谓的面向连接的特性。

a、TCP 提供可靠交付。通过 TCP 连接传输的数据,无差错、不丢失、不重复、并且按序到达。

UDP 继承了 IP 包的特性,不保证不丢失,不保证按顺序到达

b、TCP 是面向字节流的,发送的是一个流,没头没尾。之所以变成流,是TCP状态维护做的事情。

UDP 继承了 IP 包的特性,基于数据报的,一个一个地发,一个一个地收。

c、TCP 是可以有拥塞控制的。就会根据网络环境和丢包情况调整自己的行为

UDP 就不会根据网络环境和丢包情况调整自己的行为

d、TCP是有状态的服务;UDP是无状态的

2、UDP包头

UDP 包到达目标机器后,发现 MAC 地址匹配,于是就取下来,将剩下的包传给处理 IP 层的代码。把 IP 头取下来,发现目标 IP 匹配;在 IP 头里面有个 8 位协议,这里会存放,数据里面到底是 TCP 还是 UDP

无论是 TCP 还是 UDP 包头里面应该有端口号,根据端口号,将数据交给相应的应用程序

a、源端口号和目标端口号(16位)

b、UDP长度和校验和(16位)

3、UDP 的三大特点

a、沟通简单

b、轻信他人。不会建立连接,虽然有端口号,但是监听在这个地方,谁都可以传给他数据,他也可以传给任何人数据,甚至可以同时传给多个人数据

c、不会根据网络的情况进行发包的拥塞控制

3、UDP 的三大使用场景

a、需要资源少,在网络情况比较好的内网,或者对于丢包不敏感的应用

b、不需要一对一沟通,建立连接,而是可以广播的应用

c、需要处理速度快,时延低,可以容忍少数丢包,但是要求即便网络拥塞,也毫不退缩,一往无前的时候

d、实际应用场景:

i.网页或者 APP 的访问(HTTP3)QUIC(全称Quick UDP Internet Connection,快速UDP互联网连接)是谷歌提出的一种基于UDP协议改进的通信协议,其目的是降低网络通信的延迟,提供更好的用户互动体验。

ii.流媒体的协议(直播领域)

当网络不好的时候,TCP 协议会主动降低发送速度,这对本来当时就卡的看视频来讲是要命的,应该应用层马上重传,而不是主动让步。因而,很多直播应用,都基于UDP 实现了自己的视频传输协议

iii.实时游戏(游戏领域)

如果出现一个数据包丢失,所有事情都需要停下来等待这个数据包重发。客户端会出现等待接收数据,然而玩家并不关心过期的数据,激战中卡 1 秒,等能动了都已经死了。游戏对实时要求较为严格的情况下,采用自定义的可靠 UDP 协议,自定义重传策略,能够把丢包产生的延迟降到最低,尽量减少网络问题对游戏性造成的影响。

三、TCP协议

1、TCP包头格式

a、源端口号和目标端口号(16位)

b、包的序号和确认序号(解决乱序和确认送达)

c、状态位SYN 是发起一个连接,ACK 是回复,RST 是重新连接,FIN 是结束连接)引起双方连接状态变更

d、窗口大小::控制流量

TCP 包头很复杂,但是主要关注五个问题,顺序问题,丢包问题,连接维护,流量控制,拥塞控制

2、TCP的三次握手

a、TCP三次握手:请求 -> 应答 -> 应答之应答

b、为什么不是两次握手?两端消息都要有去有回才能建立连接

 c、一开始,客户端和服务端都处于 CLOSED 状态。先是服务端主动监听某个端口,处于LISTEN 状态。然后客户端主动发起连接 SYN,之后处于 SYN-SENT 状态服务端收到发起的连接,返回 SYN,并且 ACK 客户端的 SYN,之后处于 SYN-RCVD 状态。客户端收到服务端发送的 SYN 和ACK 之后,发送 ACK 的 ACK,之后处于 ESTABLISHED 状态,因为它一发一收成功了。服务端收到 ACK 的 ACK 之后,处于 ESTABLISHED 状态,因为它也一发一收了。
 

3、TCP的四次挥手

a、当 A 说“不玩了”,就进入 FIN_WAIT_1 的状态

b、B 收到“A 不玩”的消息后,发送知道了,就进入 CLOSE_WAIT 的状态
c、A 收到“B 说知道了”,就进入 FIN_WAIT_2 的状态

i.如果这个时候 B 直接跑路,则 A 将永远在这个状态。TCP 协议里面并没有对这个状态的处理,但是 Linux 有,可以调整tcp_fin_timeout 这个参数,设置一个超时时间。
ii.如果 B 没有跑路发送了“B 也不玩了”的请求,此时B从CLOSE_WAIT 的状态结束进入LAST-ACK状态

d、A收到“B 也不玩了”的请求,然后发送“知道 B 也不玩了”的ACK 后,从 FIN_WAIT_2 状态结束

e、A 最后等待一段时间 TIME_WAIT(等待的时间设为 2MSL,MSL是Maximum Segment Lifetime,报文最大生存时间),这个时间要足够长,长到如果 B 没收到 ACK 的话,“B 说不玩了”会重发的,A 会重新发一个 ACK 并且足够时间到达 B,最后CLSOED

f、B收到A的发送的“知道 B 也不玩了”后,结束LAST-ACK状态,进入CLOSED

(如果A没有等待直接CLOSED,就会出现两种情况:

i. B没有收到A的发送的“知道 B 也不玩了”,会再发送一个“B 也不玩了”的请求,但是A已经关闭了,所以B再也收不到ACK了

ii.A 直接关闭之后,A 的端口就直接空出来了,但是 B 不知道,B 原来发过的很多包很可能还在路上,如果 A 的端口被一个新的应用占用了,这个新的应用会收到上个连接中 B 发过来的包,虽然序列号是重新生成的,但是这里要上一个双保险,防止产生混乱,因而也需要等足够长的时间,等到原来 B 发送的所有的包都死翘翘,再空出端口来)

4、TCP的可靠性保证

a、累计确认(解决粘包问题,滑动窗口):TCP 协议使用的也是发送-应答的模式。为了保证顺序性每一个包都有一个 ID。在建立连接的时候,会商定起始的 ID 是什么,然后按照 ID 一个个发送为了保证不丢包,对于发送的包都要进行应答,但是这个应答也不是一个一个来的,而是会累计接收多个包后应答某个之前的 ID,表示都收到了,这种模式称为累计确认或者累计应答(cumulative acknowledgment)

b、顺序问题与丢包问题:确认与重发的机制(滑动窗口)

i.超时重传:当报文发出后在一定的时间内未收到接收方的确认,发送方就会进行重传(通常是在发出报文段后设定一个闹钟,到点了还没有收到应答则进行重传)。

ii.快速重传的机制:当接收方收到一个序号大于下一个所期望的报文段时,就检测到了数据流中的一个间格,于是发送三个冗余的 ACK客户端收到后,就在定时器过期之前,重传丢失的报文段

iii.还有一种方式称为Selective Acknowledgment (SACK)。这种方式需要在 TCP 头里加一个 SACK 的东西,可以将缓存的地图发送给发送方。例如可以发送 ACK6、SACK8、SACK9,有了地图,发送方一下子就能看出来是 7 丢了

c、流量控制(滑动窗口)

接收端处理数据的速度是有限的,如果发送方发送数据的速度过快,导致接收端的缓冲区满,而发送方继续发送,就会造成丢包,继而引起丢包重传等一系列连锁反应。
因此TCP支持根据接收端的处理能力,来决定发送端的发送速度,这个机制叫做流量控制。tcp通过滑动窗口来进行流量控制

d、拥塞控制问题(滑动窗口)

总结:TCP的可靠性保证:

  • 通过序列号和确认应答信号确保了数据不会重复发送和重复接收。
  • 同时通过超时重发控制保证即使数据包在传输过程中丢失,也能重发保持数据完整。
  • 通过三次握手,四次挥手建立和关闭连接的连接管理保证了端对端的通信可靠性。
  • TCP还使用了滑动窗口控制提高了数据传输效率
  • 通过流量控制控制发送者的发送速度从而使接收者来得及接收,防止丢包。
  • 通过拥塞控制就是防止过多的数据注入到网络中,避免网络中的路由器或链路不致过载,导致数据丢失。从而保证了TCP传输的可靠性。

四、套接字Socket

在讲 TCP 和 UDP 协议的时候,我们分客户端和服务端,在写程序的时候,我们也同样这样分。

Socket可以作插口或者插槽讲。可以把软件程序想象为弄一根网线一头插在客户端,一头插在服务端,然后进行通信。所以在通信之前,双方都要建立一个 Socket。

Socket 编程进行的是端到端的通信,能够设置的参数,也只能是端到端协议之上网络层和传输层的。

网络层:Socket 函数需要指定到底是 IPv4 还是 IPv6,分别对应设置为 AF_INET 和AF_INET6。传输层:还要指定到底是 TCP 还是 UDPTCP 协议是基于数据流的,设置SOCK_STREAM,而 UDP 是基于数据报的,因而设置为SOCK_DGRAM。

1、基于 TCP 协议的 Socket 程序函数调用过程

监听的 Socket 和真正用来传数据的 Socket 是两个,一个叫作监听 Socket,一个叫作已连接 Socket。

2、基于 UDP 协议的 Socket 程序函数调用过程

UDP 是没有连接的,所以不需要三次握手,也就不需要调用 listen 和 connect,但是,UDP 的的交互仍然需要 IP 和端口号,因而也需要bind。UDP 是没有维护连接状态的,因而不需要每对连接建立一组 Socket,而是只要有一个 Socket,就能够和多个客户端通信。也正是因为没有连接状态,每次通信的时候,都调用 sendto 和 recvfrom,都可以传入 IP 地址和端口

3、服务器如何接更多的项目

a、将项目外包给其他公司(多进程方式)

相当于你是一个代理,在那里监听来的请求。一旦建立了一个连接,就会有一个已连接Socket,这时候你可以创建一个子进程,然后将基于已连接 Socket 的交互交给这个新的子进程来做

在 Linux 下,创建子进程使用 fork 函数。通过名字可以看出,这是在父进程的基础上完全
拷贝一个子进程。在 Linux 内核中,会复制文件描述符的列表,也会复制内存空间,还会
复制一条记录当前执行到了哪一行程序的进程。显然,复制的时候在调用 fork,复制完毕
之后,父进程和子进程都会记录当前刚刚执行完 fork。这两个进程刚复制完的时候,几乎
一模一样,只是根据 fork 的返回值来区分到底是父进程,还是子进程。如果返回值是 0,
则是子进程;如果返回值是其他的整数,就是父进程。

b、将项目转包给独立的项目组(多线程方式)

创建进程相当于成立新公司,购买新办公家具,而创建线程,就相当于在同一个公司成立项目组。
一个项目做完了,那这个项目组就可以解散,组成另外的项目组,办公家具可以共用。

在 Linux 下,通过 pthread_create 创建一个线程,也是调用 do_fork。不同的是,虽然新
的线程在 task 列表会新创建一项,但是很多资源,例如文件描述符列表、进程空间,还是
共享的,只不过多了一个引用而已。

c、一个项目组支撑多个项目(IO 多路复用,一个线程维护多个Socket)

当然,一个项目组可以看多个项目了。这个时候,每个项目组都应该有个项目进度墙,将自
己组看的项目列在那里,然后每天通过项目墙看每个项目的进度,一旦某个项目有了进展,
就派人去盯一下。
由于 Socket 是文件描述符,因而某个线程盯的所有的 Socket,都放在一个文件描述符集
合 fd_set 中,这就是项目进度墙,然后调用 select 函数来监听文件描述符集合是否有变
化。一旦有变化,就会依次查看每个文件描述符。那些发生变化的文件描述符在 fd_set 对
应的位都设为 1,表示 Socket 可读或者可写,从而可以进行读写操作,然后再调用
select,接着盯着下一轮的变化。
d、一个项目组支撑多个项目(IO 多路复用,从“派人盯着”到“有事通知”)

项目组不需要通过轮询挨个盯着这些项目,而是当项目进度发生变化的时候,主动通知项目组,然后项目组再根据项目进展情况做相应的操作。能完成这件事情的函数叫 epoll,它在内核中的实现不是通过轮询的方式,而是通过注册callback 函数的方式,当某个文件描述符发送变化的时候,就会主动通知。

假设进程打开了 Socket m, n, x 等多个文件描述符,现在需要通过 epoll 来监听是否这些 Socket 都有事件发生。其中 epoll_create 创建一个 epoll 对象,也是一个文件,也对应一个文件描述符,同样也对应着打开文件列表中的一项。在这项里面有一个红黑树,在红黑树里,要保存这个 epoll 要监听的所有 Socket。当 epoll_ctl 添加一个 Socket 的时候,其实是加入这个红黑树,同时红黑树里面的节点指向一个结构,将这个结构挂在被监听的 Socket 的事件列表中。当一个 Socket 来了一个事件的时候,可以从这个列表中得到 epoll 对象,并调用 call back 通知它。这种通知方式使得监听的 Socket 数据增加的时候,效率不会大幅度降低,能够同时监听的Socket 的数目也非常的多了。上限就为系统定义的、进程打开的最大文件描述符个数。因而,epoll 被称为解决 C10K 问题的利器。



 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值