netstat命令
-n.拒绝显示别名,能显示数字的全部转化成数字(IP+PORT)
-l 仅列出有在 Listen (监听) 的服务的状态
-p 显示建立相关链接的程序名(pid)
-t 仅显示tcp相关选项
-u 仅显示udp相关选项
2.1.全双工和半双工的区别
全双工:可以双方同时传输数据,UDP协议和TCP都是全双工
半双工:一次只能一方传输数据;
2.2.UDP的特点
1.无连接:知道对端的IP和端口号就直接进行传输, 不需要建立连接 ;
2.不可靠:没有应答机制和重传机制;
3.面向数据报:不能够灵活的控制读写数据的次数和数量 ;
1.必须接受一个完整的报文,不能分两次接受半个报文在拼接;
2.UDP一次只能发送2^16个字节大小的数据,如果超过只能在应用层拆分,再在对端的应用 层合并;
2.3.UDP协议格式
16位源端口号:发送端端口号
16位目的端口号:接受端端口号
16位UDP长度:UDP首部(UDP报头)+UDP数据(UDP有效载荷);整个数据报的总长度
16位UDP检验和:如果校验和出错, 就会直接丢弃;
2.4.UDP的缓冲区
过程:调用系统接口read把缓冲区的数据拷贝到应用层,write直接向内核交付数据
UDP协议只有接受缓冲区:因为没有重传机制和应答机制;
3.1.tcp协议格式
16位源端口号:发送端端口号
16位目的端口号:接受端端口号
TCP的报头标长是20字节;
4位首部长度:4个比特位可以表示0-15;报头长度=首部长度*4;所以最大的报头为4*最大首 部长度(15)=60;报头长度在20-60可以被4整除的数;
序号:每个报文都会被设置一个序号;一个报文在发送缓冲区最大那一个下标,下面这个报文的序号是1000;
确定序号:表示确定序号之前的序号对应的报文被对端接受了;例:确定序号101,表示101序号以前的序号对应的报文都被接受了,下次使用101序号传输;
收到确定报文表示确认序号以前的序号已经被接收;并且确定报文中16位窗口大小被设置表示接收端的接受缓冲区还有多少空间,
如果没收到确定报文,发送端默认对端没有收到将重传;
TCP协议有两个缓冲区:发送缓冲区和接受缓冲区
过程:调用read实际就是把数据拷贝到发送缓冲区,write把数据从接受缓冲区拷贝到应用层
特点:
1. 效率提高 ,因为应用层把数据拷贝到发送缓冲区就结束了就返回;
2. 应用层和传输层的解耦 ,因为应用层把数据拷贝到发送缓冲区,数据就不用应用层管理
标志位的概念:用于区分不同的报文,确定报文、连接报文等等;
一个标志是3个英文字母总共3字节,有6位的标志位有6字节,所以一次最多设置2个标志,也可以一个都不设置;
6个标志:
前4个标志在3次握手4次挥手讲
ACK: 设置与否表示确认序号是否有效
SYN: 请求建立连接; 我们把携带SYN标识的称为 同步报文段 FIN: 通知对方, 本端要关闭了, 我们称携带FIN标识的为 结束报文段 RST: 对方要求重新建立连接; 我们把携带RST标识的称为 复位报文段
URG: 紧急指针是否有效 PSH: 接收端的接收缓冲区快满了发送端没法传输数据了,提示接收端应用程序立刻从TCP缓冲区把数据读走;
URG(不是很重要):优先先读URG报文不用按序到达,只会读被紧急指针下标的那个字节
TCP协议会统计正常通信的时间;来设置一个超时重传的时间
3次握手过程
3.7.1.第一个原因:3次握手是最小次数,可证明全双工的双端的网络通信信道是正常
3.7.1第二个原因:防止SYN洪水;
1/2握手server端会先于client端建立连接;
那么client端可以无消耗让server建立一个与client的连接并管理起来(消耗server资源);
3.8.1.TIME_WAIT为什么要有这个状态
不能直接CLOSED因为还有给对端发送ACK;
3.8.2.TIME_WAIT需要等多久呢?为什么?
等待时间:需要等2倍MSL时间;
MSL(maximum segment lifetime)时间:MSL在RFC1122中规定为两分钟,但是各操作系统的实现不同, 在Centos7上默认配置的值是60s,并且TCP协议也有自己的一套方法,统计多个正常一次通信的时间,取最大的一个做MSL;
为什么是2MSL
一个来回是2MSL,ACK没被接受就会重发FIN,刚好一个来回的时间2MSL;
2MSL保证历史发的数据在网络中消散:如果server不等待2MSL直接断开,对面没有收到ACK,将会重发FIN,server立马重连收到重发的FIN又会断开不符合我的要求;
3.8.3.CLOSE_WAIT
如果服务器端,在客户端请求关闭连接,服务器端accept的文件描述符不关闭,会在保持CLOSE_WAIT状态(文件描述符泄漏)
服务器端:只能accept的文件描述符但是不处理
int main()
{
int listen_sock=socket(AF_INET,SOCK_STREAM,0);
//bind服务器
struct sockaddr_in local;
local.sin_family=AF_INET;
local.sin_port=htons(PORT);
local.sin_addr.s_addr=INADDR_ANY;
bind(listen_sock,(struct sockaddr*)&local,sizeof(local))
listen(listen_sock,5);
struct sockaddr_in tmp;
socklen_t tlen=sizeof(tmp);
//建立连接
int fd=accept(listen_sock,(struct sockaddr*)&tmp,&tlen);
}
滑动窗口的作用:发送报文不用立即ACK可以继续发送一些报文
滑动窗口的大小:
跟接收端的窗口大小(接收缓冲区)有关;
在3次握手就设置好了滑动窗口的大小;
滑动窗口大小不是一直不变的;window_start+=ACK(不一定是一个报文可能是多个),window_end+=接收端的16位窗口大小;
三部分依次:1.以确认的报文;2.已发送/可以发送但是没有收到ACK的报文;3.还不能发送的报文
因此TCP支持根据接收端的处理能力(窗口大小), 来决定发送端的发送速度. 这个机制就叫做流量控制(Flow Control);
在3次握手就设置好了滑动窗口的大小就是依靠流量控制;
如果接收端的窗口满了就会返回的窗口大小为0;发送端定期发送一个窗口探测报文(标志位设为PSH并且不携带数据);
连续收到3个及以上的确认序号的ACK,那么会重发下一个,这种机制被称为 "高速重发控制"(也叫 "快重传");
再开始通信时,并不知道网络情况怎么样,是否拥塞;所有不能通信一开始就发送大量的数据,免得已经拥塞的网络,更加拥塞;
过程(慢启动:前面慢后面快):拥塞窗口初始化时为1;先按指数增长,碰见网络拥塞时,把拥塞窗口的一半做为阈值;
再把阻塞窗口置为1,先按指数增长达到阈值,再按线性增长,再次碰见网络阻塞;(循环这一步)
滑动窗口大小=min(阻塞窗口,接受端的窗口大小);
3.11.1延迟应答
原因:如果接收数据的主机立刻返回ACK应答, 这时候返回的窗口可能比较小(接受端的应用层也在read数据);
窗口越大, 网络吞吐量就越大, 传输效率就越高. 保证网络不拥塞的情况下尽量提高传输 效率;
也是有限制的,一般数量(多少个报文就返回一个ACK)限制:2,时间限制:最大延迟时间:200ms;不同的操作系统可能不同;
3.11.2.捎带应答
携带数据的报文并设置ACK标志位,大多数的报文都是这样的;
tcp的接受缓冲区是一串连续的字节数据,没有区分的边界,如何把一个个数据包分离出来:
从应用层来解决:
特殊字符
自描述字段
固定长度
http就是使用特殊字符+自描述字段来处理粘包问题的;
空行分离报文和有效载荷
如果存在Content-length自描述字段,那么就有有效载荷并且Content-longth的数值表示有效载荷的字节数;
3.12.1.UDP有粘包问题吗?
A:没有;
表示报头中包含一个16位UDP长度表示UDP报文有多少字节数,并且UDP报头是固长8字节的,UDP长度- 8=一个数据包;UDP的接受缓冲区一次只会交付给应用层一个数据包;