课程链接地址
2.2.2 Posix API与网络协议栈
- posix api: linux一开始仿unix不同版本,提供 操作系统——应用程序接口的标准
- 上一次2.1.1的reactor.c优化1048576数组
1 建立连接,api
所有linux 上运行的都用的这些api,不管java还是python,底层linux的api都是一样的
-
服务端
socket()返回fd;bind绑定一个接口;listen;accept创建一个客户端的fd;recv;send;close
epoll; fcntl设置阻塞非阻塞
客户端
socket(); bind()可选不一定绑; connect(); send ; recv; close
tcp传输——建立连接,传data,断连接
tcp连接准备
-
**socket()**如何实现/组成的
好有意思,socket 插座 = 插fd int型+ 座tcp控制块
分配fd,用bitmap算法——如果置0 未用,置1用过了
tcp是不断alloc创建新的
-
bind()
还没到tcp连接,跟tcp还没关系这步
传入fd,绑定一个ip地址+port 五元组:源 目的 ip+端口+协议;本质是个设置set初始化过程
客户端如果未绑,会随机分配端口,一路,就绑定;一般就默认分配
-
listen()监听
tcp状态迁移图
- 把tcp里的status状态设置为listen,如果未设置,会拒接消息请求,代表迎宾小姐姐正式上岗
- 分配全连接syn,半连接队列queue
listen以后才能三次握手建立连接
server不可以先发起,只能client发起,不管应用层用的什么语言,见posix API与网络协议栈的实现原理.pdf
-
client发:两个字段——syn这位置1**,seqnum32位,置为1234 随机值**,好处避免被截获破解包
解析完知道这是握手的包
-
server回:四个字段——acj置1, acknum是1235(seqnum+1),代表1235以前所有包收到了,syn这位置1, seqnum 5647也是随机的
-
client回:ack ,acknum 5648(5647+1)承认server都收到了之前的包
为什么三次:脑经急转弯
核心是如何记这个三次握手图
tcp是全双工长期通信——1234 client告诉server发的data从哪里开始; 5647 server告诉client发的data从哪里开始
这两个data开始地方id很重要:确保data不重复,不丢失
三次握手发生在what函数
-
client的conncet
-
server端连接前listen()准备,连接结束accept()取出连接,被动触发
man listen 可以看listen函数解释 int listen(int sockfd, int backlog)
为什么backlog,因为类似古代的虎符,和去吃饭叫号的牌子,确保你拿的号不是自己编的没造假,两次:一半给你client,一半自留
半连接syn队列:在server为多个client创建半连接,半个虎符 号牌
全连接accept队列:三次握手结束后的accept这里,半连接syn队列的半个虎符move到,不是copy到accept队列
问题
-
tcp连接生命周期when开始?
**从第一次握手server的listen接收到syn包,**协议栈为client分配一个连接节点,连接开始(但是要等到三次握手结束,accept()函数创建的时候fd开始)
-
第三次握手client来一个data包, server如何从syn半连接队列查找匹配的节点 然后放到accept队列里(半个虎符)
通过(源、目的 * 端口 、ip ,协议)五元组查出来
-
如何防护syn泛洪——client在syn创建连接节点,但是后面不继续发data,那么就不会syn队列里节点move到accept队列,然后syn队列就炸了
listen(fd, backlog) listen函数,tcp协议栈在1980s就有了,比我年纪大
用第二个参数backlog设置的是什么?
-
最早syn半连接队列长度,防止无限增长炸了
比较鸡肋,因为防火墙 从物理上接收data前server已经能有这个效果的,物理上隔了防止泛洪
-
syn + accept 队列总长度 = 未分配fd的tcb的数量
TCB的全称是“Trusted Computing Base”,指的是在计算机系统中,确保系统安全性的核心部分。它包括硬件、固件和软件组件,用于保护系统免受各种安全威胁。
防止accept一直不处理会积累大量连接堆着
-
accept 队列(pending connections 待连接)长度
大大提升建链的速率(现在的方法), 连接的吞吐量
-
accept()
上面listen()函数讲完了
-
分配fd给对应server
-
fd与tcb(accept队列中节点)建立映射
在epoll()的listen返回epollIN事件
listenfd 用的 accept()
clientfd 用的 recv(), send()
如果ET边沿触发,如何处理所有连接?
多个事件但是只触发一次,有问题,用while(1) 设置accept非阻塞,直到fd=-1,break