(Linux网络协议)网络基础(应用层、传输层)

应用层

直面程序员的一层,因为应用程序时程序员自己写的,因此应用层的协议都是程序员自己决定的。

自定制协议

程序员自己根据自己的应用特点,定义协议(数据的格式 / 数据的描述信息)
在这里插入图片描述
序列化:将各个数据对象按照指定的协议组织成为持久化存储 / 数据传输的二进制数据串。(json序列化、protobuf、二进制序列化)。
反序列化:将二进制数据串按照指定协议解析得到各个数据对象。

一个序列化方式的好坏有很多的评定标准:解析性能、传输性能等。

知名协议

HTTP协议:超文本传输协议,早期专门用于传输超文本数据html,但是随着协议发展多元化,不限制数据格式。
网址- - -统一资源定位符:URL- - - 在网络中唯一标记定位一个资源。

如何定位 - - - URL中包含的元素

协议方案名称 : // 认证用户名:认证密码@服务器IP地址 : 服务器处理进程端口 / 请求的资源路径?查询字符串#片段标识符
http://username:[email protected]:80/index.html?name=dz&age=16#ch

服务器IP地址:我们看到的不一定是IP地址,也可能是一个域名,服务器的别名,通过域名解析服务器就能得到服务器IP地址;
服务器端口:web服务器默认http服务端口时80端口,默认不显示;
/请求的资源路径:资源在服务器上的路径,这里的 / 是http根目录,但是是一个服务器上的相对根目录,只是一个子目录;
查询字符串:客户端提交给服务端的一些数据,由 key=val&key=val 形式的键值对组成;(查询字符串中不能出现特殊字符,因为URL中特殊字符都有特殊含义,提交的数据有特殊字符会造成歧义,若提交的数据中有特殊字符,则需要进行数据转义)。

urlencode:url编码,将特殊字节每一个字节转化成16进制的数字字符,并且使用%前缀作为转义标识。(如 + -> %2b)
urldecode:url解码,在url中遇到%,则认为其后两个字符需要转义,将第一个字符转换成数字乘以16(左移4位),加上第二个字符转换的数字。
片段标识符:html中的一个标签id,直接跳转到页面的某个位置。

HTTP协议实现

wireshark:网络抓包工具,抓取流经网卡的所有数据流量(什么包都能抓);
fiddler:浏览器的代理工具,通过代理实现数据抓包(专业的http抓包工具);

https就是加密后的http协议,若要抓取 https 的数据包,则需要进行配置
在这里插入图片描述

HTTP协议格式

请求

  • 首行:GET http://123.456.58.25/admin HTTP/1.1 ,以空格间隔包含三个要素,并且最终以 \r\n 作为结尾;
    请求方法:GET/POST/HEAD/DELETE/CONNECT/PATCH/OPTIONS/TRACE
    GET- - - 请求实体资源,也可以通过url中查询字符串向服务器提交数据,数据不安全,url长度有限制(各个服务器应用商的限制);
    POST - - - 主要用于向服务器提交数据,提交的数据在正文中; GET/POST:GET请求没有正文,POST请求有正文;
    HEAD- - - 类似于GET,只是相较于GET,head只要响应头部,而不响应正文;
    URL: http://123.456.58.25/admin
    协议版本: HTTP/1.1 - - - 0.9/1.0/1.1/2.0
    0.9:这时候的http仅用于传输html数据,只有GET请求方法,并且协议格式不完整;
    1.0:正是规定了http协议格式,增加了多种请求方法,并且支持了不同文件格式的数据流;
    1.1:在1.0的基础上增加了更多请求方法和头部描述信息,并且支持了长连接,管线化传输;
    2.0:采用二进制流传输,可以多路复用,并且允许服务端主动推送数据;
    短连接:http基于在传输层tcp实现通信,短连接指的是建立连接,发送一个请求,得到相应之后,则关闭连接;
    长连接:一次连接可以发送多条请求。
    在这里插入图片描述

  • 请求头部:描述本次请求的关键字段信息,由key:val形式的键值对组成,并且为每个键值对以\r\n作为结尾 key:val\r\n key:val\r\n
    connection 控制长/短连接/ cache-Control缓存控制 / User-Agent 客户端的属性 / Accept 描述自己所能接收的数据属性 / Content-Length描述正文长度 / Content -Type描述符正文数据类型 / Cookie(早期http是短连接通信,是一个无状态协议,不会保存客户端的状态,每次访问都需要进行登录,因此引入了Cookie保存客户端状态);
    Cookie:可以带有一些信息,持续在通信中描述客户端的通信状态,但是不够安全;
    空行:间隔头部与正文,\r\n;接收http数据的时候,当连续接收两个\r\n (\r\n\r\n)的时候,则认为头部到此结束;
    先获取完整头部,通过头部中的Content-Length获取正文长度,然后获取指定长度正文,通过这种方式每次获取完整一条http请求数据
    正文:提交给服务端的数据

  • 响应

  • 首行:HTTP/1.1 303 See Other,包含三个要素,以空格进行间隔,以\r\n作为结尾
    协议版本:0.9 / 1.0 / 1.1 / 2.0
    响应状态码:表示本次的请求服务端所作出的响应结果
    1xx:描述信息
    2xx:表示本次请求正确处理完毕,典型:200
    3xx:重定向,你请求的资源在另一个位置,要求客户端重新请求新的位置,301(永久),302(临时)
    4xx:表示客户端请求错误,400(请求错误),404(请求的资源不存在)
    5xx:表示服务端错误;500(服务器内部错误),502(代理请求失败/无效响应),504(代理请求超时)
    状态码描述:对状态码的描述信息,可以是官方文档对应描述,也可以是自定义

  • 头部:关于本次响应的一些关键字段描述信息,以key:val键值对组成,以\r\n作为结尾
    Transfer-Encoding:实体正文的传输方式 / Expires:缓冲过期时间 / Location-3xx重定向的新位置
    Set-Cookie:服务端通过set-cookie向客户端传递信息,会被保存在客户端浏览器的cookie文件中
    Cookie:客户端每次通信从cookie文件读取数据通过cookie向服务端传递信息(维持客户端状态信息)
    cookie的使用不够安全,因此使用Session搭配使用
    Session:会话,服务端会为每个登录的客户端创建会话,在服务端描述一些会话信息(客户端身份信息,状态信息),保存在服务端,可以通过cookie将session id 返回给客户端,客户端每次通信都会通过cookie带有自己的session id;
    cookie和session有什么区别?
    答:cookie持续传递客户端状态信息的字段,cookie是保存在客户端上的数据,用于持续与服务端进行信息统一的一种手段;session是一种会话的控制,服务端保存的会话信息包含客户端的身份状态信息,通过cookie/set-cookie传递的session id 进行客户端的身份状态识别

协议的特性总是影响着上层程序的编写,而协议的特性又来源于协议的实现

传输层

负责应用程序之间的数据传输(通过端口的描述- - -描述哪两个进程在进行通信)- - - UDP/TCP

UDP:无连接,不可靠,面向数据报

udp协议报头只有8个字节
在这里插入图片描述
无连接:不需要建立连接,只要知道对方的地址信息就能直接发送数据;
不可靠:udp在传输层不保证数据安全有序到达对端,需要程序员在应用层进行包序管理;
面向数据报:有最大长度限制的传输方式,取决于数据报长度字段,因为长度字段只有16位,因此数据报总长度不能大于64k,也就是说sendto接口给予的数据长度不大于64k-8k(报头占8个字节);
因此若传输的数据比较大,则需要程序员在应用层进行分包操作,并且进行包序管理

udp通信在报头中确定了数据报长度,因此udp的数据传输是整条收发的
发送:sendto给予的数据放到发送缓冲区后就会直接封装头部,进行发送
接收:recvfrom 总是只能接收一条完整的数据,而不会出现接收半条或者多条的情况
因此recvfrom 给予的缓冲区一定要足够大,若给予的缓冲区大小小于一条数据的长度,则recvfrom就会报错(因为udp无法交付半条数据);

TCP协议:面向连接,可靠传输,面向字节流

在这里插入图片描述
面向连接:连接建立成功之后才能进行数据通信,tcp 有自己的连接管理(三次握手建立连接/四次挥手断开连接);
在这里插入图片描述

为什么握手是三次?挥手是四次?
答:因为2次不安全,4次没必要;tcp通信需要确保双方都具有数据收发的能力,因此双方都发送SYN确保对方具有通信能力;四次挥手:发送FIN包,只能表示对方不再发送数据了,不表示对方不再接受数据,因此被关闭方进行ACK回复之后有可能还会继续发送数据,等到不再发送数据了,才会发送下一个FIN包,因此FIN和ACK是分开的。

TIME_WAIT状态有什么用,为什么主动关闭方法没有直接进入close释放资源?
假定主动关闭方最后一次的ACK丢失,被动关闭方法没有收到最后一次ACK,超时后就会重传一个FIN;假定客户端没有TIME_WAIT 直接释放资源,就可能启动新的客户端使用与之前客户端相同的地址信息。

  • 1、刚启动新的客户端绑定地址成功,收到重传的FIN包,对新连接造成影响;
  • 2、新启动的客户端,若是向相同的服务端发送SYN,因为服务端处于LAST_ACK要求的是ACK而不是SYN,因此就会发送RST;
    因此若主动关闭方最后一次回复后直接释放资源,就有可能会对新启动的新连接造成影响,因此必须等待一段时间,能够处理有可能重传的FIN。
    等待的时间多长比较合适:2个MSL时间 - - - MSL(报文最大生存周期);
    1.处理重复的FIN包 / 2.等待本次通信的所有报文都消失在网络中,避免对新连接造成影响;

tcp三次握手失败,服务端是如何处理的?

  • 1、没有收到SYN,什么都不做
  • 2、回复了SYN+ACK但是,长时间没有收到响应,则超时后发送RST重置连接报文,释放资源;

一台主机上出现大量的TIME_WAIT是什么原因?如何处理?

  • TIME_WAIT是主动关闭方出现的,一台主机出现大量的TIME_WAIT 证明这台主机上大量的主动关闭了连接,常见于一些爬虫服务器。
  • 处理:
    1、调整TIME_WAIT等待时间,也可以使用开启地址重用的套接字选项 - setsockopt/
    2、地址重用:允许套接字绑定使用中的地址端口,常用于防止socket处于TIME_WAIT无法使用相同地址信息进行绑定新的套接字。

一台主机上出现大量的CLOSE_WAIT是什么原因?如何处理?

  • CLOSE_WAIT是被动关闭方收到FIN请求进行回复之后的状态,等待上层程序进行进一步处理,若出现大量CLOSE_WAIT,有可能是被动关闭方主机上程序中忘了最后一步断开连接后调用close释放资源;

tcp连接管理中的保活机制

tcp通信中,若两端长时间没有数据往来,则这段时候每隔一段时间,服务端向客户端发送一个保活探测数据报,要求客户端进行回复,若连接多次没有收到响应,则认为连接断开。

长时间没有数据往来:默认7200s,可通过设置套接字选项进行配置;
每隔一段时间:默认75s,可通过设置套接字选项配置;
连续多次无响应:默认9次,可通过设置套接字选项设置;
连接断开对接收端的影响:recv会返回0 ;
连接断开对发送端的影响:send触发异常 - - - SIGPIPE

可靠传输

  • 1、面向连接
  • 2、确认应答机制,发送数据后要求对方进行确认回复,才能知道对方是否收到了这条数据,通过序号与确认序号实现;
  • 3、超时重传机制,发送数据等待却响应超时之后(默认一般在200ms左右),认为数据丢失,则进行重新传输;
  • 4、通过序号/确认序号字段实现数据有序交付
  • 5、通过校验和字段校验数据一致性,不一致则要求对方进行重传;

在这里插入图片描述
seq:本次数据的起始序号;
ack:对方发送数据的确认序号,告诉对方确认序号之前的数据我收到了;

  • 三次握手时,双方会协商起始序号(上图中是从0开始,但是实际中可能是一个随机值),三次握手中,虽然数据长度为0,但是确认序号是对方发送的起始数据序号+1;
  • 数据通信时,确认序号是对方发送数据中的起始序号加上数据长度,告诉对方这个确认序号之前的数据都已经收到了;(这么做的目的是为了防止因为确认回复的丢失而导致的重传)
    就算是因为网络原因,后发的数据先到了,接收方也会根据协商的起始序号,根据每条数据中的起始序号,将数据在接收缓冲区中进行排序;

避免因为一些原因导致丢包

1、额外的丢包问题处理

  • 1、发送方发送数据过快,接收方来不及处理取出,接收缓冲区满溢,则以后的数据都会被丢弃;
  • 2、发送方发送大量数据,但是因为网络状态不好导致大量丢包造成重传;

2、滑动窗口机制:依靠协议中的窗口大小字段实现流量控制
接收方通过协议中的窗口大小字段,告诉发送方,最多可以发送多少数据(窗口大小不大于接收方缓冲区剩余空间大小);
MSS:最大数据段大小,表示tcp数据通信时一条数据的最大大小,通信时双方进行协商,取双方MSS中较小的一方作为最大数据段大小;
在这里插入图片描述
在这里插入图片描述
滑动窗口在发送方维护发送窗口 / 接收方维护接收窗口 - - -窗口通过一个后沿序号 / 前沿序号实现
窗口大小不能大于接收方的接收缓冲区中剩余空间的大小 - - - 避免了发送的数据太多而缓冲区满了没处放导致的丢包;

发送窗口:表示一次最多从后沿到前沿发送多少数据,不超过接收方窗口大小;

  • 后沿:所要发送数据的起始序号,后沿的移动取决于能否收到数据确认回复;
  • 前沿:根据接收方窗口大小计算的结束序号,取决于接收方响应的窗口大小(前沿减去后沿的大小就等于接收方的窗口大小);

接收窗口:表示从哪里开始接收数据,接收到多少序号为止,不超过剩余空间大小(进行包序管理,哪个包应该放在缓冲区的什么位置)

  • 后沿:接收数据是起始序号,后沿的移动决定于是否收到了后沿的数据;
  • 前沿:根据接收缓冲区剩余空间大小计算得到的接收的数据的结束序号,前沿的移动取决于缓冲区中剩余空间大小。

滑动窗口机制允许发送端根据窗口大小以及mms连续发送多条数据,一旦丢包:

  • 停等协议:得到一条回复,然后才能发送下一条数据;
  • 回退n步协议:一条数据丢失了,则需要发送端将丢失的这条数据以后的数据都进行重传;
  • 选择重传协议:一条数据丢失了,则仅仅针对丢失的这条数据进行重传;
    因为网络状态不好,导致发送的数据越多丢包的越多:拥塞控制
    拥塞控制:进行网络探测,以一种慢启动、快增长的传输方式,进行根据网络状态调整发送速度的机制;

提高传输性能的方式

  • 快速重传机制:发送端连续发送多条数据,若接收端接收数据并非是接收后沿数据,则认为有可能后沿数据丢失了,首先不会接收到数据的确认回复,其次向发送间隔连续发送三次后沿数据的重传请求,要求对方对后沿数据进行重传;
    发送方连续收到三条同一重传请求,则对这条数据进行重传

为什么是三次:避免因为网络延迟,数据报的延迟到达,三次可以有一个缓冲时间,若在第二次的时候收到了后沿数据报,则不再发送第三条重传请求,这时候发送端也就不用重传了;
快速重传可以一定程度避免发送端必须的超时重传;

  • 延迟应答机制:接收方接收到数据之后,并不立即进行确认回复(因为如果立即进行确认回复,接收缓冲区剩余空间变小了,窗口就变小了,导致传输的吞吐量变小),而是延迟应答,则有可能应答的时候程序上层已经将数据取出,保证窗口大小不会变小。
  • 捎带应答机制:接收方接收到数据之后,进行确认回复,确认回复就是一个报头中的确认序号进行的,为了减少空报头的响应占据带宽,则使用捎带应答,在即将发送的数据头部中进行上一条接收到的数据的确认回复。

可靠传输实现:面向连接 / 确认应答 / 超时重传 / 序号 / 确认序号 / 校验和
避免丢包重传:滑动窗口机制 / 拥塞机制
挽救传输性能:快速重传 / 延迟应答 / 捎带应答 / 延迟发送

面向字节流:字节流传输服务- - -面向连接的,有序的一种最小以字节为传输单元的传输方式;

  • 发送端在send发送数据的时候,并不会立即封装报头,而是将数据先放到发送缓冲中,选择合适的时候再去从缓冲区中取出合适大小的数据进行传输;
  • 接收端在recv接收数据的时候,并非一条一条向上交付,而是根据recv想要的数据长度从接收缓冲区中取出指定长度的数据进行交付;
  • 优点:传输比较灵活,大量小的数据会集合成一条大的数据进行一次性传输,减少了IO次数,提高性能(延迟发送可以关闭,可配置的),接收方接收也更加灵活,想要多少取多少;
  • 缺点:tcp交付的这条数据可能并非一条完整的数据,也有可能是多条数据,(tcp对于上层给予的数据边界并不敏感,不关注是几条数据,只关注自己可以传输多少字节的数据 / recv 想要多少字节的数据 - - - 反之udp对每条数据有边界区分,每次刚好就只交付一条完整的数据),导致上层将多条数据当做一条数据进行处理。
tcp粘包问题

tcp有可能将多条数据当做一条数据进行处理(udp是不会出现粘包问题的,因为udp头部中定义了数据报长度)

粘包的解决方案(程序员在应用层进行数据的边界管理)

  • 1.每条数据之间以特殊字符进行间隔 - - - 缺陷:如果数据中有这个特殊字符,就需要进行转义处理;
  • 2.数据定长传输 - - - 缺陷:数据短小的情况下进行补位,传输了大量的无用数据;
  • 3.应用层协议头部中定义数据长度 - - -http / udp
    http如何解决粘包的:http头部以 \r\n\r\n 特殊字符间隔表示结束,并且在头部中通过Content-Length确定正文长度;
    udp如何解决粘包的:在传输层就进行了粘包的解决,头部定长8字节,头部中定义数据报长度;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章