TCP通信流程详解

news2024/10/6 5:59:08

目录

什么是TCP协议?

三次握手和四次挥手

TCP通信流程:

socket():

bind():绑定函数

listen():监听函数

accept():和客户端建立连接

connect():客户端连接服务器函数

read()/recv():读取函数

write() /send():写入函数

close():关闭连接

为什么服务器端有bind()函数而客户端没有?

什么是TCP协议?

        TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的传输协议,它是OSI(Open System Interconnection,开放式系统互联)模型中的第四层协议,通常使用于网络中的应用层和传输层之间。

TCP协议的特点有:

        1. 面向连接:通信前需要先建立连接,传输完成后再释放连接。传输数据时有三次握手和四次挥手过程。

        2. 可靠传输:采用确认应答机制和重传控制,确保数据传输的可靠性和完整性。

        3. 流量控制:通过滑动窗口技术,控制发送方发送数据的速度,避免接收方处理不过来而出现数据丢失的情况。

        4. 拥塞控制:根据网络拥塞情况调整发送数据的速度。当网络拥塞时,TCP协议会通过减小发送窗口或延迟发送数据的方式来降低网络拥塞程度。

        5. 面向字节流:TCP协议是以字节流的形式传输数据,而不是以数据包为单位传输。因此,应用层需要自己处理数据包的边界。

        TCP协议常用于HTTP、FTP、Telnet等传输层协议中,因为这些协议需要传输大量的数据并要求传输的数据准确无误。

三次握手和四次挥手

        TCP三次握手和四次挥手是TCP协议的基本特性,用于在建立和终止TCP连接时进行协商。以下是TCP三次握手和四次挥手的详细步骤:

TCP三次握手:

        1. 客户端向服务器发送一个 SYN 报文段,请求建立连接。

        2. 服务器收到 SYN 报文段后,回复一个 SYN ACK 报文段,表示收到请求并准备好连接。

        3. 客户端收到 SYN ACK 报文段后,回复一个 ACK 报文段,表示确认连接已建立。

TCP四次挥手:

        1. 客户端向服务器发送一个 FIN 报文段,请求关闭连接。

        2. 服务器收到 FIN 报文段后,回复一个 ACK 报文段,表示已经收到请求。

        3. 服务器在关闭连接前,需要先发送一个 FIN 报文段,表示可以关闭连接。

        4. 客户端收到 FIN 报文段后,回复一个 ACK 报文段,表示已经收到请求,然后在一段时间后关闭连接。

        需要注意的是,TCP协议通过三次握手建立连接后,客户端和服务器之间可以进行多次数据传输。在数据传输完成后,通过四次挥手来关闭连接。

TCP通信流程:

TCP通信流程大致如下:

        1. 建立连接:发送方和接收方通过三次握手建立TCP连接。首先,发送方向接收方发送SYN(同步)报文,表示请求建立连接;接收方收到SYN报文后,向发送方回送ACK(确认)和SYN报文,表示接收方已经准备好建立连接;发送方再回送ACK报文,表示连接建立成功。

        2. 数据传输:连接建立成功后,发送方可以向接收方发送数据。TCP协议会将数据分成若干个数据段,每个数据段有编号,并且会保证按序传输,确保数据的可靠性。

        3. 确认接收:接收方收到数据后,会向发送方发送ACK确认报文,表示成功接收数据。

        4. 关闭连接:一旦数据传输完成,发送方和接收方都可以向对方发送FIN(结束)报文,表示要关闭连接。当一方收到FIN报文后,会回送ACK报文确认收到,同时关闭自己的连接。当另一方收到ACK报文后,也关闭自己的连接,这样双方的连接就完全关闭了。(四次挥手)

 socket():

        socket()函数用于创建一个新的socket(套接字),并返回其文件描述符。socket()函数的语法如下:

int socket(int domain, int type, int protocol);
//domain:指定socket所属的协议族,常见的取值有AF_INET(IPv4协议)、AF_INET6(IPv6协议)等。
//type:指定socket的类型,常见的取值有SOCK_STREAM(流式套接字,用于TCP协议)和SOCK_DGRAM(数据报套接字,用于UDP协议)等。
//protocol:指定协议类型,通常设置为0(默认值),表示使用默认的协议。

        socket()函数返回新创建的socket的文件描述符,如果创建失败,则返回-1并设置errno错误码,表明失败的原因。

        需要注意的是,创建socket后,需要调用bind()函数将socket与一个本地地址(IP地址和端口号)绑定,并调用connect()函数或listen()函数启动socket的监听或发起连接。在使用完socket后,需要调用close()函数关闭socket,以释放相关资源。

bind():绑定函数

        bind()函数用于将一个socket(套接字)与一个本地地址(IP地址和端口号)绑定。在客户端中,通常不需要使用bind()函数,因为内核会自动分配一个可用端口给客户端socket。但在服务器程序中,需要使用bind()函数将socket与一个已知的IP地址和端口号绑定,以便客户端可以通过该地址和端口号来连接服务器。bind()函数的语法如下:

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
//sockfd:要绑定的socket文件描述符。
//addr:指向数据结构struct sockaddr的指针,该结构体包含IP地址和端口号信息。
//addrlen:sockaddr结构体的长度

        bind()函数返回0表示绑定成功,否则返回-1并设置errno错误码,表明绑定失败的原因。通常情况下,如果没有权限或者指定的端口号已经被占用,bind()函数会失败。

        需要注意的是,在服务器程序中,bind()函数通常需要在调用listen()函数之前调用,以便指定监听的地址和端口号。而在客户端程序中,不需要调用bind()函数,因为内核会自动为客户端分配一个可用端口号。

listen():监听函数

        listen()函数是用于TCP服务器端的系统调用函数,它将一个套接字标记为被动套接字(passive socket),即该套接字用于等待客户端的连接请求。listen()函数的语法如下:

int listen(int sockfd, int backlog);

//sockfd:要监听的套接字的文件描述符。
//backlog:指定连接请求的队列长度,即等待被服务程序接受的连接请求的最大个数。这个参数的值应该大于等于0,通常取值为5或者10。

        listen()函数返回0表示成功,返回-1表示失败,并设置errno错误码,表示失败的原因。

        调用listen()函数后,服务器端进程就可以通过accept()函数接受客户端套接字的连接请求。需要注意的是,listen()函数并不阻塞,它仅仅是将套接字标记为被动套接字,并将该套接字加入内核管理的监听列表中,客户端连接请求实际上是在accept()函数中被处理的。

accept():和客户端建立连接

        accept()函数是一个阻塞函数,它使服务器进程进入了等待状态,直到有客户端发起连接请求。如果有连接请求到来,该函数会返回一个新的套接字描述符,用于和客户端进行通信。可以在accept()函数调用之前设置一个超时时间,以避免服务器长时间等待连接请求而陷入死循环。

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
//sockfd:指定欲等待接受连接的套接字描述符。
//addr:指向用于存放远程主机地址信息的结构体指针,可以为 NULL。
//addrlen:指向一个整型变量,表示 addr 所指向的地址结构体的长度。如果 addr 为 NULL,则该参数无用。

返回值:

- 成功:返回新创建连接的套接字描述符;
- 失败:返回 -1,错误类型存于 errno 中。

        请注意,在使用accept()函数时,服务器进程应当针对每一个客户端连接创建一个新的进程或线程,以充分利用系统资源,避免阻塞其他客户端的请求。此外,服务器进程还应该对每个客户端进行必要的身份验证和数据传输的安全处理。

connect():客户端连接服务器函数

connect() 函数用于向指定的地址发起连接请求。

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
//sockfd:指定客户端使用的套接字描述符。
//addr:指向服务器端地址信息的结构体指针。
//addrlen:表示 addr 所指向的地址结构体的长度。

返回值:

- 成功:0;
- 失败:返回 -1,错误类型存于 errno 中。

read()/recv():读取函数

        read() 函数是 UNIX 系统提供的标准 I/O 函数,它用于从文件描述符(包括网络套接字)中读取数据。在使用 TCP 套接字时,read() 函数一般会阻塞,直到接收到足够的数据或发生错误。read() 函数的语法如下:

ssize_t read(int fd, void *buf, size_t count);
//fd 表示要读取的文件描述符
//buf 表示读取到的数据存放的缓冲区
//count 表示要读取的数据大小。

        recv() 函数它也用于从网络套接字中读取数据,并且相比于 read() 函数更加常用。在使用 TCP 套接字时,recv() 函数一般也会阻塞,直到接收到足够的数据或发生错误。除此之外,recv() 函数还可以设置一些可选的参数,例如在接收数据时指定 MSG_DONTWAIT 标志可以使 recv() 函数变成非阻塞模式。recv() 函数的语法如下:

ssize_t recv(int sockfd, void *buf, size_t len, int flags);
//sockfd 表示要读取的套接字文件描述符
//buf 表示读取到的数据存放的缓冲区
//len 表示要读取的数据大小
//flags 是可选参数,可以用来控制 recv() 函数的行为,例如指定 MSG_DONTWAIT 标志可以使 recv() 函数变成非阻塞模式。

write() /send():写入函数

        write() 函数是 UNIX 系统提供的标准 I/O 函数,它用于向文件描述符(包括网络套接字)中写入数据。在使用 TCP 套接字时,write() 函数一般会阻塞,直到数据被写入或发生错误。write() 函数的语法如下:

ssize_t write(int fd, const void *buf, size_t count);
//fd 表示要写入的文件描述符
//buf 表示要写入的数据的缓冲区
//count 表示要写入的数据大小。

        send() 函数是 Socket API 中的函数,它也用于向网络套接字中写入数据,并且相比于 write() 函数更加常用。在使用 TCP 套接字时,send() 函数一般也会阻塞,直到数据被写入或发生错误。除此之外,send() 函数还可以设置一些可选的参数,例如在写入数据时指定 MSG_DONTWAIT 标志可以使 send() 函数变成非阻塞模式。send() 函数的语法如下:

ssize_t send(int sockfd, const void *buf, size_t len, int flags);
//sockfd 表示要写入的套接字文件描述符
//buf 表示要写入的数据的缓冲区
//len 表示要写入的数据大小
//flags 是可选参数,可以用来控制 send() 函数的行为,例如指定 MSG_DONTWAIT 标志可以使 send() 函数变成非阻塞模式。

close():关闭连接

        在使用网络套接字时,close() 函数一般会等待发送缓冲区中的数据全部发送完毕或超时之后才会关闭套接字。close() 函数的语法如下:

int close(int fd);
//fd 表示要关闭的文件描述符。

使用 close() 函数关闭套接字时,还应该注意一些问题:

        1. 确保在所有的读写操作都已经执行完毕之后再关闭套接字。
        2. 在关闭套接字之前,应该通过调用 shutdown() 函数发送一个 FIN 数据包,以便正确地关闭 TCP 连接。关闭套接字之后,不应该再次通过该套接字进行读写操作。
        3. 在使用多线程或多进程时,应该注意避免同时关闭同一套接字,以避免出现竞争条件。

为什么服务器端有bind()函数而客户端没有?

        在网络编程中,服务器端必须绑定一个端口号来监听客户端的连接请求。bind() 函数用于给服务器端套接字绑定指定的 IP 地址和端口号,这样客户端才能够通过这个 IP 地址和端口号来连接服务器。

        而客户端并不需要绑定指定的 IP 地址和端口号,因为客户端只需要通过指定服务器的 IP 地址和端口号来连接服务器即可。因此,客户端没有 bind() 函数。

总结:本文详细讲述了TCP协议的通信流程和具体的函数如何使用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/575333.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第63篇:美国NSA量子注入攻击的流量特征及检测方法

Part1 前言 大家好,我是ABC_123,公众号正式更名为”希潭实验室”,敬请关注。前不久花时间研究了美国NSA的量子注入攻击手法,并在Hackingclub山东济南站技术沙龙做了分享。对于这种攻击手法部分网友嗤之以鼻,认为是老美…

Linux下的进程状态和 僵尸/孤儿进程的区别

目录 Linux进程的各种状态的表示: R状态的测验: S状态的测验: T状态的测验: 这次讲解一个新指令:kill -l t状态测验:追踪暂停 X状态:死亡状态 Z状态:僵尸状态 进程一直处于…

过孔焊盘~尺寸、间隙、通流能力

过孔焊盘 导通孔(via)焊盘尺寸 a) 外层焊盘环宽(A)要大于5mil,内层焊盘环宽(A)要大于8mil, 推荐导通孔孔径及焊盘尺寸如下: b) 推荐反焊盘大小尺寸≥过孔焊盘+20MIL。 走线与金属化孔间的最小间隙 推荐的走线距金属…

Roblox 不但不支持 Linux,还屏蔽了 Wine

导读据悉,Roblox 不但不支持 Linux,还屏蔽了 Wine。 Roblox 不但不支持 Linux,还屏蔽了 Wine 多人游戏 Roblox 没有 Linux 原生版本,但之前可以通过 Wine 在 Linux 上运行。不过其最新的反作弊软件专门屏蔽了 Wine 应用&#xff…

XuperChain共建守护者系列藏品震撼发行,最新合成玩法揭秘

5月30日上午10点,百度超级链重磅推出「XuperChain共建守护者系列」藏品。「XuperChain共建守护者徽章系列」自身具有权益,也可与共建徽章系列藏品合成新藏品,玩法多多、福利多多,等你探索! 共建守护者系列共计20款藏品…

智能集成接口:I3 ISA-95 的应用

介绍 多年来,使用基于制造运营管理 (MOM) 的应用程序的制造 IT 顾问试图说服制造商这些类型的应用的高价值。实时 MOM 解决方案是唯一一组能够精确优化工厂日常运营的 IT 应用程序,可为其可用性流程带来可创造的价值,…

《操作系统》期末客观题梳理

《操作系统》复习(1-9) 文章目录 《操作系统》复习(1-9)Ⅰ知识点概念第一章操作系统导论第二章进程描述与控制第三章处理机调度死锁第四章进程同步第五章存储器管理第六章虚拟存储器第七章输入输出系统第八章文件管理第九章磁盘存…

探索无限可能:物联网技术的未来应用引领智能化时代

⭐ 物联网技术⭐ 物联网技术的应用⭐ 物联网发展和创新挑战 当我们回顾过去几十年的科技发展,不难发现物联网技术的崛起和蓬勃发展。物联网的概念已经成为当今科技领域的热门话题,它正在以惊人的速度渗透到我们的日常生活中。从智能家居到智能城市&#…

【C++】map容器

更明确的类型重命名规则using 在C语言中typedef将一个变量提升为一种类型: typedef int * p;//p是int*类型//int Array[10];//Array是一个可装10个int类型变量的数组。typedef int Array[10];//Array是一个可装10个int类型变量的数组的类型//Array arr;…

[golang 微服务] 1.单体式架构以及微服务架构介绍

一.单体架构 在了解微服务之前首先看看单体架构,单体架构在 中小企业内部用的是非常多的,当 业务不复杂, 团队规模不大的时候,单体架构比微服务架构具有 更高的生产率,比如2017年前的淘宝都是单体架构 单体架构的程序部署在单台服务器 这种架…

计算机网络考试多选题汇总Ⅱ

https://cadyin.blog.csdn.nethttps://blog.csdn.net/qq_38639612?spm1010.2135.3001.5421 计算机网络考试多选题汇总 1、在Windows中,任务管理器的作用是() A.终止未响应的应用程序 B.终止进程的运行 C.查看系统当前的信息 …

Springboot服务端接口公网远程调试,并实现HTTP服务监听

文章目录 前言1. 本地环境搭建1.1 环境参数1.2 搭建springboot服务项目 2. 内网穿透2.1 安装配置cpolar内网穿透2.1.1 windows系统2.1.2 linux系统 2.2 创建隧道映射本地端口2.3 测试公网地址 3. 固定公网地址3.1 保留一个二级子域名3.2 配置二级子域名3.2 测试使用固定公网地址…

Hybrid Shuffle 测试分析和使用建议

摘要:Apache Flink 社区在 1.16 版本引入了 Hybrid Shuffle Mode [1],它是传统的 Batch Shuffle 和 Pipelined Shuffle 的结合,让 Flink 批处理具备了更强大的能力。Hybrid Shuffle 的核心思想是打破调度约束,根据可用资源的情况来…

vue 获取url地址的参数

url是一个 URL地址,我们在使用 vue的时候,经常需要获取 url的参数,获取方法有很多种,这里我只介绍一种获取 url参数的方法,那就是使用 Requests. urlset. newContext ()方法。 这个方法就是调用…

华为OD机试真题B卷 Java 实现【内存资源分配】

一、题目描述 有一个简易内存池,内存按照大小粒度分类,每个粒度有若干个可用内存资源,用户会进行一系列内存申请,需要按需分配内存池中的资源,返回申请结果成功失败列表。 分配规则如下: 分配的内存要大…

论文浅尝 | 大规模知识图谱中的知识图谱补全和多跳推理

笔记整理:刘健宇,东南大学硕士,研究方向为知识图谱规则学习与推理 链接:https://dl.acm.org/doi/abs/10.1145/3534678.3539405 动机 知识图谱(KG) 以头-关系-尾三元组的形式捕获知识,是许多人工智能系统中的重要组成部…

chatgpt赋能python:Python文件另存为教程:让文件保存到你想要的地方

Python 文件另存为教程:让文件保存到你想要的地方 最近,我看到有人在问如何使用Python来另存文件。对于许多初学者或非技术人员来说,这可能看起来很困难,但实际上,Python 提供了一些非常简单的方法来达到这一目的。下…

产品发布+联合演讲+认证+奖项丨云和恩墨在openGauss Developer Day 2023主论坛大放异彩...

openGauss Developer Day 2023 5月26日,一场数据库开发者年度盛会「openGauss Developer Day 2023」在北京昆泰嘉瑞文化中心成功召开。大会汇聚产学研用各界知名专家分享 openGauss 社区的技术创新、优秀实践和生态成果,吸引了线上线下数千名开发者、技术…

大手笔!微软一口气发布了 3 款开发者工具。。

公众号关注 “GitHubDaily” 设为 “星标”,每天带你逛 GitHub! 昨天我发了一篇 Build 大会相关的生产力产品,介绍了未来 Windows 将集成的一系列 AI 特性,以及如何帮助人们更好的利用 AI,辅助完成各类繁琐的工作。 今…

Go1.21 速览:正式结束对 macOS 10.13 和 10.14 的支持

大家好,我是煎鱼。 根据 Go 语言的版本发布规律,一般是 2 月份和 8 月份各会发布一个新的版本。当前是 Go1.20。也就是在 8 月份会发布 Go1.21 这一个新版本。 在这个新版本,将会正式的结束对 macOS 10.13 和 10.14 的支持,并禁用…