当前位置: 首页 > news >正文

网络学习-TCP协议(七)

一、TCP协议

TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。

1、三次握手

在这里插入图片描述

客户端:
1、先发起连接,发送SYN置1,seqnum=12345(随机值)----半连接建立,形成syn队列

服务端:
1、收到SYN,分配tcp控制块
2、发送ack置1,acknum=12346, syn,seqnum=34531(随机值)

客户端:
2、发送ack,acknum=34532 ,seqnum=12346(从之前的序列号+1) ----半连接转为全连接,进入accept队列

小结:

可见在TCP协议中,服务端是被动连接。

2、四次挥手

注意只有主动方和被动方:

1、主动发起断开连接,发送FIN置1,seqnum=1234(随机值)
2、被动方收到FIN,发送ack置1,acknum=1235(seq+1)
3、被动方发送FIN,seqnum=5678(随机值)
4、主动方收到FIN,发送ack置1,acknum=5679(seq+1)

3、TCP的格式

在这里插入图片描述

首部开销最小20字节,最大60字节

4、网络协议栈

在这里插入图片描述

应用层:http,ftp,ssh
传输层:TCP,UDP
网络层:IP,ICMP

5、TCP发生在哪些函数中:

通过对网络I/O的学习,发现无论使用select,poll,还是epoll,都没看见TCP/UDP的相关字眼,那电脑是如何判断使用哪种协议来实现连接的?
回顾之前代码,主要使用了socket()bind(), listen(), accept(), connect(), send(), recv(), **close()**这几个函数。

  • 这些函数是如何实现TCP连接的?
  • 这些函数编译生成的执行文件,为什么在不同系统平台可以正常运行?

二、POSIX API

1、什么是POSIX API?

  • 是一套可移植操作系统接口标准,旨在使应用程序可以在多种UNIX和类UNIX操作系统上运行而无需修改。
  • 像之前使用的socket()bind(), listen(), accept(), connect(), send(), recv(), close()fcntl()select,poll,epoll等函数,都是POSIX API的一部分。

2、三次握手的过程,发送在哪些函数里面:

  • 客户端:
    client:
    Connet()

  • server:
    listen();
    accept();

3、API简介

1. socket()

int socket(int domain, int type, int protocol);
/*
*socket英文单词的本意是插座,在网络编程中,socket代表网络IO的建立,实质是(fd,tcp控制块--stream)
*功能:
*分配fd,bitmap
*tcp控制块的分配
*domain:通信协议族,AF_INET, AF_UNIX,AF_INET6,大部分都是基于IPV4的网络通信,通常使用AF_INET
*type:指定套接字类型,SOCK_STREAM(字节流)---TCP协议,SOCK_DGRAM(报文)---UDP协议,SOCK_RAW---原始套接字
*protocol:指定具体的协议,通常为0。前两个参数确定了,第三个参数通常为0,由内核自动选择合适的协议
*返回值:成功返回非负文件描述符,失败返回-1
*/

2. bind()

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
/*
1、绑定固定ip,port
2、还未到tcp建立过程
3、属于设置过程
返回值:成功返回0,失败返回-1
*/

3. listen()

int listen(int sockfd, int backlog);
/*
1、设置监听,等待客户端连接
2、backlog:半连接队列的大小(内核参数,默认值5)
3、TCP开始建立
返回值:成功返回0,失败返回-1
实质:
1、把TCP的status设置为TCP_STATUS_LISTEN
2、如果不设置,强行连接,会被拒绝
3、设置tcp全连接队列和半连接队列tcp->syn_queuetcp->accept_queue
*/

4. accept()

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
/*
1、阻塞等待客户端的连接请求
2、属于建立TCP的完成后
返回值:成功返回非负文件描述符,失败返回-1
实质:
分配fd给客户端,并把客户端的fd和tcp控制块绑定EPOLLLT:水平触发
只要有事件就绪就会一直通知EPOLLET:边缘触发
只有当事件发生时才会通知一次
避免不能及时响应需要额外添加while循环进行处理
while(1){fd = accept(listenfd, NULL, NULL);if(fd < 0) {break;}
}
*/

5. connect()

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
/*
1、主动发起tcp连接
2、属于建立TCP的过程
返回值:成功返回0,失败返回-1
*/

6. send()

ssize_t send(int sockfd, const void *buf, size_t len, int flags);
/*
flags:用于指定发送数据的特殊选项,如MSG_DONTWAIT,非阻塞模式,一般默认为0
1、发送数据到对方
2、属于传输层
返回值:成功返回发送的字节数,失败返回-1
实质:
将数据从用户空间拷贝到内核缓冲区,然后通过网络发送到对方的内核缓冲区(协议栈),异步操作
*/ssize_t write(int fd, const void *buf, size_t count);
/*
1、发送数据到对方
返回值:成功返回发送的字节数,失败返回-1
相比于send,少了一个flags参数,其余相同,send是POSIX API,write是标准C库函数
如果是网络编程,推荐使用send,因为send可以指定flags参数
*/

7. recv()

ssize_t recv(int sockfd, void *buf, size_t len, int flags);
/*
flags:用于指定接收数据的特殊选项,如MSG_WAITALL,阻塞直到所有数据都收到
1、接收数据
2、属于传输层
返回值:成功返回接收的字节数,失败返回-1
实质:
将对方内核缓冲区的数据拷贝到用户空间缓冲区,异步操作
*/
ssize_t read(int fd, void *buf, size_t count);
/*
1、接收数据
返回值:成功返回接收的字节数,失败返回-1
相比于recv,少了一个flags参数,其余相同,recv是POSIX API,read是标准C库函数
如果是网络编程,推荐使用recv,因为recv可以指定flags参数
*/

8. close()

int close(int fd);
/*
1、关闭fd,释放bitmap位图资源
2、如果是TCP连接,会发送fin包给对方,等待对方的ack包
3、如果是UDP连接,直接释放资源
返回值:成功返回0,失败返回-1
实质:
回收fd,释放bitmap位图资源
如果是tcp连接,发送fin包给对方,等待对方的ack包
如果是udp连接,直接释放资源
*/int shutdown(int sockfd, int howto);
/*
howto:用于指定关闭哪一部分连接,SHUT_RD(关闭读),SHUT_WR(关闭写),SHUT_RDWR(同时关闭读写)
1、关闭fd,释放bitmap位图资源
2、如果是TCP连接,可以指定只关闭读或者写
返回值:成功返回0,失败返回-1
实质:
回收fd,释放bitmap位图资源
如果是tcp连接,可以选择只关闭读或者写
不推荐使用,关闭连接就关闭了,使用shutdown,还只关闭一部分连接,容易引起混乱
*/

三、总结

1、在TCP传输过程中,服务端属于被动连接,客户端属于主动发起连接。

2、对于不同的系统平台,使用了POSIX API,可以实现跨平台网络编程。

四、拓展问题

1、tcp连接的生命周期从什么时候开始?

tcp连接的生命周期是从三次握手开始,到四次挥手结束。即客户端调用connect()开始,到服务端调用close()结束。

2、第三次握手数据包,如何从半连接队列查找匹配的节点

源端口,目的端口,源ip,目的ip

3、syn泛洪攻击

  • 定义:
    syn泛洪攻击是一种常见的网络攻击手段,其目的是通过发送大量的TCP连接请求(SYN包),耗尽服务器的资源,从而阻止合法的用户建立正常的TCP连接。
  • 解决方案:
    早期系统版本,通过listen(fd, backlog)第二个参数,控制半连接队列的大小
    然后是将半连接队列的大小设置为syn+accept队列总长度,放未分配fd的tcb的数量
    现在大部分系统是将半连接队列的大小设置为accept队列长度

4、为什么建立连接需要三次握手,而断开连接需要四次挥手?

  • 三次握手:
    为了实现数据的可靠性传输;TCP通信协议双方,都必须维护一个序列号,以标识发送出去的数据包,哪些是已经被对方收到。实质上是通信双方相互告知序列号的起始值,并确认对方已经收到了这个序列号。如果是两次握手,至多只有连接发起方的序列号能被确认,而另一方的序列号无法被确认。
  • 四次挥手:
    为了保证数据完整性,TCP协议需要通过四次挥手来正确关闭连接。主动方发送FIN包后,被动方需要先回复ACK确认收到,然后再发送自己的FIN包给主动方,最后等待主动方的ACK确认收到后才真正断开连接。这样可以确保双方都能够正确地关闭连接,避免数据丢失

5、accept发生在三次握手的哪一步

发生在第三次握手之后,TCP建立完成之后。

6、TCP是如何保证顺序的?

通过序列号、确认应答、重传机制、滑动窗口和拥塞控制等多种机制来保证数据的顺序性。

7、ack没有收到,先收到fin怎么办?

继续发ack

8、双方调用close会发生什么?

结论:服务端会出现大量的TIME_WAIT状态

  • ​双方发送FIN报文,都进入FIN_WAIT_1状态
  • ​双方收到FIN并发送ACK,都进入closing状态
  • ​双方收到ACK并进入TIME_WAIT状态,等待2MSL(最大段生存时间)以确保对方收到ACK。
  • ​连接完全关闭,2MSL超时后,双方都进入CLOSED状态,连接完全关闭。

相关文章:

  • 深度解析:SQLynx 如何筑牢数据库安全防线​
  • 敦煌网测评从环境搭建到风控应对,精细化运营打造安全测评体系
  • 使用 GPUStack 纳管摩尔线程 GPU 进行大语言模型和文生图模型的推理
  • 相同,对称,平衡,右视图(二叉树)
  • 全国青少年信息素养大赛-python编程—省赛真题—卡牌游戏
  • 国产高云FPGA实现MIPI视频解码+图像缩放,基于OV5647摄像头,提供Gowin工程源码和技术支持
  • LVS + Keepalived + Nginx 高可用负载均衡系统实验
  • 学习黑客 tcpdump
  • 如何在UI设计中更好地平衡美学与功能性?
  • IP-guard发布新版本4.87.2241.0
  • css 里面写if else 条件判断
  • [Windows] 格式工厂 FormatFactory v5.20.便携版 ——多功能媒体文件转换工具
  • 禅道——安装PHP的ioncube扩展
  • wordpress上传图片时出现服务器无法处理图片
  • 高通usecase理解
  • 对接钉钉消息样例:DING消息、机器人
  • iOS 直播弹幕礼物功能详解
  • 多模态AI终极形态?GPT-5与Stable Diffusion 3的融合实验报告
  • 【49. 字母异位词分组】
  • iOS 上线前的性能与稳定性检查流程实录:开发者的“最后一公里”(含 KeyMob 应用经验)
  • wordpress一键环境搭建/成都优化官网公司
  • 做一家算命的网站/培训机构优化
  • 模板网恋/潮州seo建站
  • 上海做电缆桥架的公司网站/今日国际新闻摘抄
  • 邯山区建设局网站/360浏览器网页版入口
  • 网络广告的特征是()多选题/seo专员是什么意思