本文已参与「新人创作礼」活动,一起开启掘金创作之路。
计算机网络概述
网络层通过调制解调负责传送和接受0和1的电信号,以太网协议规定,怎样的一组0和1的电信号是有含义的,因此把一组电信号按规定叫一帧,每一帧分为标头和数据,标头包含发送者、接受者和数据类型,数据即数据内容,那么发送者和接受者的信息如何标识,就是MAC地址 每个网卡出厂,都有独一无二的MAC地址,根据ARP协议,每个网卡能够知道别人的MAC地址 那知道了MAC地址,怎么发送过去,实际上最原始的是在我的网络范围内,给所有人都发一份,每个人收的时候看接受者是不是我自己,但是这种广播的形式效率很低,如果要发的很远,我们不在一个子网里,那就没法传了,但MAC地址没法区分各个MAC地址是否在一个子网里,于是就有了IP协议,IPv4规定,每个网卡都有一个IP地址,一共32位,假设前24位代表网络部分,后8位代表主机部分,如果前24位相同,代表我们在一个子网里,但实际上我们并不知道到底多少位代表网络,多少位代表主机,因此有了子网掩码 假设前24位是网络,后8位是主机,那么我的子网掩码就是255.255.255.0,也就是前24位是全1,后8位是全0,两台主机将ip地址与子网掩码相AND,如果结果相同,那就说明两台主机在一个子网内 每一台计算机有了ip地址,大家知道谁和自己在一个子网,网关在哪,就可以根据IP协议发送数据包了,IP数据报也分为标头和数据,标头记录了版本、长度、Ip地址等,把IP数据包直接放进以太网协议的数据部分 现在任意两台计算机已经能互相传输了,但计算机上有很多应用程序,我送过来的数据是给哪个应用程序的?这就需要端口了,端口在0-65535之间,0-1023被占用,剩下的用于程序传输,这就是传输层干的事,实现了程序与程序之间的通信,这样通信时,最开始使用UDP传输,UDP数据报也包含标头和数据,标头里有两个端口号,数据部分是发送的内容,现在把IP数据内容里用UDP数据包替换就完成了 但这样一直都存在一个问题,我发出去了,你收到了没,我不知道,因此就有了TCP协议
各层协议
应用层 DNS域名解析 HTTP超文本传输 FTP文件传输 传输层 TCP传输控制 UDP用户数据报 网络层 IP网络间互联 ARP从IP->物理地址 RIP网关和主机路由选择 数据链路层 以太网
http
首先根据域名,找ip地址,先在浏览器缓存里找,再在系统DNS缓存里找,再在路由缓存里找,
再在互联网服务提供商的DNS缓存里找->com顶级域名服务器->权威服务器,直到找到ip
然后浏览器和web服务器建立一个TCP连接,三次握手
建立好连接后,发送一个http请求,http请求由一个请求行,请求头,空行和请求数据组成
请求行又分为,请求方法,URL,http版本
请求方法又分为,get post put delete head等,比如说从浏览器输入网址,都是get方式
服务器把URL定位的资源放在响应报文的数据部分回给客户端
请求头包含了主机地址,连接属性,编码、数据压缩、语言等
请求数据不在get里用,只在post里用
之后服务器响应http请求,响应由一个状态行,响应头,空行和相应数据组成
状态行包括http协议版本,状态码
响应头包含服务器软件名,版本,正文的类型长度编码压缩格式语言
相应数据HTML
浏览器拿到HTML代码就解析,解析到资源,就向服务器请求
关闭TCP,渲染呈现
https
与http相比,https更安全, 客户端先喝Web服务器建立SSL Web服务器将网站的公钥给客户端 然后大家协商一个安全等级,根据这个安全等级,客户端用公钥加密密钥,服务器根据私钥解密
TCP
三次握手四次挥手
序列号seq:数据分好几包有编号,我这包里第一个数据的编号 确认号ack:想收到的对方下一个报文的字节编号,也就是seq+1是我希望看到的 ACK:确认号,为1表示ack有效 SYN:建立连接时用来同步 FIN:用来释放连接
客户端在connect时,服务端被动打开,进入listen,TCP报文标志位SYN标志为1,产生一个序号值seq,保存在tcp首部的序列号字段里,指明客户端打算连接的服务器端口,并将该数据包发送给服务器端,发送完毕后,客户端进入SYN_SEND,表示我想连接 服务端发一个ACK+SYN,ack=seq+1,seq=y,服务器进入SYN_RECV,表示我收到你的连接请求了 客户端收到SYN+ACK包后,ack=y+1,服务端和客户端进入established
客户端在断开连接时,先FIN=1表示要释放连接,seq=u为上一个收到的报文的最后一个字节的序号的下一号,此时客户端进入FIN_WAIT_1,表示我要从这断开连接了 服务端收到后,发一个ACK+SYN,ack=u+1,seq=v,服务端进入CLOSE_WAIT,关闭等待 客户端收到服务端的报文后,进入FIN_WAIT_2,但什么也不发,等待服务端释放连接 服务端把最后的数据发送完了,给客户端发送一个ACK+SYN,ack=u+1,seq=w,服务端进入LAST_ACK 客户端收到服务端的ACK+SYN后,发一个ACK+SYN,ack=w+1,seq=u+1,客户端进入TIME_WAIT,等待两个最长报文段寿命,CLOSED 服务端收到这个客户端的最后一个报文后,直接CLOSED
超时重传
tcp是可靠的,收到一个包会有一个应答包,超出一定时间没有收到ack应答包,就认为传丢了,在没收到数据包和没收到ack的时候都会重传
超时时间如何设置,定义rtt为数据从一端到另一端的时间,rto为超时时间,rto略大于rtt
如果超时重传的数据又超时了,那就将rto变为2倍
快速重传
如果一次发了多分数据,某一个没收到,那就会回多个相同的ack,这意味着发送端知道了哪个包没到,就重发一个,但重发是重发这个还是把后面的也重发, 因此就有了sack
sack在tcp头部,里面记录了一些缓存,这样发送方可以知道哪些已经收到了,
滑动窗口
如果没有发送窗口和接收窗口,发送方如果收到ack,确认已经发完了,才能发下一个,但现在有了发送窗口,窗口大小如果是n个包,这n个包都可以发送,而不需要等前面的包的ack,确认已经发了,就右移发送窗口,知道碰到没发送的数据,就停止右移
发送窗口实际上是一个循环数组,最左端是已经发了收到ack的数据,右边是已经发了没有ack的数据,右边是还没发但对方能接受的数据,最右边是没法,总大小超过处理能力的数据
接收窗口的字节序列号与发送窗口一一对应,本质也是循环数组
发送窗口的大小不能大于接收窗口,否则会出现接收窗口无法完全接受数据,频繁重传浪费资源
流量控制
根据滑动窗口机制,如果你发的太快,我来不及接受,那就要重传,因此需要流量控制
假设双方三次握手后,双方的窗口大小都是400字节,发送方给接收方发了200字节,那么发送方的窗口大小-200,接收方收到200字节数据后,接受窗口-200字节,把这个200高速发送方,这时候发送方又发了200字节,但接收方此时可能只能处理100字节,接收方窗口大小为100字节,把这100字节告诉发送方,发送方继续发送100字节,接收方窗口大小为0,发送方停止发送,开始计时,每隔一段时间问你窗口大小有没有大于0
拥塞控制
流量控制从接收方与发送方避免了重传的浪费资源,拥塞控制则从整个网络层面降低网络的拥塞程度,如果已经拥塞了,再发只会更拥塞
慢启动 拥塞避免 快恢复
慢启动初始化的拥塞窗口为1个最大报文段长度,如果一直没有丢包,那就呈指数增长,直到打到了阈值,一次增长一个,如果丢包了,超时了,那发包速度立刻变为二分之一,同时阈值变为超时时的速度/2,在达到阈值以前,继续指数增长,达到阈值后,每次加一
UDP
tcp和udp区别: tcp面向连接,发送数据之前必须两端连接,建立可靠连接,仅支持点对点,面向字节流,有拥塞控制 udp无连接,不需要三次握手,想法数据直接发,能单播,多播,广播,面向报文,不可靠,高效
select
数组轮询
poll
链表轮询
epoll
事件响应+回调函数