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

muduo源码阅读:socket常见操作及一些补充

TCP连接和释放

一个典型的TCP连接、通信过程:

(假设有资源的一端是服务器端)

服务器会启用一个监听循环,不断接受client连接请求(三次握手建立连接), 进行数据通信,通信完成以后断开连接(四次挥手断开连接)。

对于client,在server启用监听循环时,向server发出连接请求,接收server数据,如有必要向server发送数据,通信完成后,断开连接。

客户端 socket,bind,connet(变为主动套接字)。服务器socket,bind,listen(变为监听套接字),accpet。

连接是指物理上一端(client)到另一端(server)的通信链路,通过server端<ip, port>与客户端<ip, port>,来唯一标识一个TCP连接。

TCP连接有长连接、短连接之分:

短连接:client和server建立连接后,一般只传递一次读写操作,然后由client发起close,发送FIN分节,关闭连接。短连接只完成一次read/write操作,就会自动关闭。

长连接:client和server建立连接后,并不会自动关闭,后续的read/write操作会继续用这个连接。长连接没有确切时间限制,可能会长时间存在。

什么是读方向,什么是写方向 ?

读方向:从TCP连接中接收数据的操作。进程从TCP连接中读取来自远端的数据。应用程序正在执行读操作,它是在接收对方发送过来的数据。

写方向:通过TCP连接发送数据的操作。进程向TCP连接中写入数据以发送给远端的应用程序。执行写操作时,你是在向对方发送数据。

为什么“方向”会是操作?

以读方向为例:应用程序从网络接收数据的过程。在这个过程中,数据是从远程主机流向本地主机的。这里的“读”实际上是一个动作或操作,它代表的是本地进程从TCP连接中获取来自远端进程的数据的行为。

两个方向并不直接指向某个实体,而是描述了数据在两个网络节点之间的流动方式以及每个节点上的应用程序如何与这种流动进行交互。

close和shutdown有什么区别?

对于TCP连接来说,正常情况下应该先关闭写方向(即不再发送数据),然后继续处理可能还在传输中的数据(读方向)(参见下一个问题)。

直接调用close()会同时关闭读写两个方向,并释放套接字相关的资源。就是说调用close的一方不能读写另一方,相当于强制关闭连接。如果TCP缓冲区有残留数据没有读或写,会直接丢失。

close关闭连接和套接字

#include<unistd.h>
int close(int fd);

close会把描述符(sockfd)引用计数-1, 当计数为0时, 才真正断开连接、关闭套接字。

(引用计数联系软链接和硬连接,shared_ptr和其他垃圾回收算法)

close终止读、写两个方向的数据传送

对读方向, 内核将套接字设置为不可读, 任何读操作都会返回异常。

对写方向, 内核尝试将发送缓冲区中的数据发送给对端, 最后发送FIN分节, 接下来如果再对该套接字进行写操作会返回异常。如果对端还继续发送数据, 就会响应RST分节。

shutdown关闭连接的一个方向, 具体取决于参数how. 成功返回0; 失败为-1, errno被设置

#include<sys/socket.h>
int shutdown(int sockfd, int how);

how有3个值:

  • SHUT_RD 关闭连接的读方向, 不能再通过套接字读取数据(读操作会直接返回EOF), 而且套接字接收缓冲区现有数据都被丢弃. 如果再收到新数据, 会对数据进行ACK, 然后直接丢弃.
  • SHUT_WR 关闭连接的写方向, 常称为"半关闭 half-close". 现有发送缓冲区的数据将会被发送掉, 后跟FIN分节. 如果程序对该套接字进行写操作, 会报错。
  • SHUT_RDWR 连接的读半部和写半部都关闭,与调用shutdown两次等效:shutdown(sockfd, SHUT_RD) + shutdown(sockfd, SHUT_WR)。

shutdown和close区别

close关闭2个方向连接, 并释放连接对应资源(套接字),而shutdown不会释放所有资源;close有引用计数的概念, 只有计数为0时, 才会释放套接字资源; shutdown没有引用计数, 是直接释放how指定的资源。close后, 只有引用计数为0时, 才会发送FIN分节。 以SHUT_WR或SHUT_RDWR为参数调用shutdown时, 总会发送FIN分节。

当服务器端调用close时,客户端对应的server fd(connet返回的文件描述符)会发生什么变化?

TCP连接的终止:

在服务器端调用 close(fd) 后,如果该 fd 是一个用于TCP通信的套接字描述符,并且这是最后一个指向该套接字的引用,那么这将启动TCP连接的正常关闭过程。服务器会尝试发送一个FIN包给客户端,表示它已经完成了数据发送。

客户端状态变化:

客户端会收到一个来自服务器的FIN包.此时,客户端的套接字进入CLOSE_WAIT状态表明它已经收到了服务器关闭其写方向的通知。

如果客户端也有数据要发送完毕,则可以继续发送直到完成。一旦所有数据发送完毕,客户端应用程序应当也调用close()来关闭其对应的套接字文件描述符,客户端发送一个FIN包给服务器,通知服务器它也不会再发送数据了。

客户端成功发送FIN后,客户端的套接字状态会从LAST_ACK转变为CLOSED,前提是它收到来自服务器对最后ACK的确认。

残留数据处理:在服务器端调用close()之后,如果还有未被客户端读取的数据留在TCP连接的缓冲区中,这些数据将会丢失,因为服务器端已明确表示不再继续该连接上的任何通信

半关闭连接:如果你只想关闭某一方向的数据传输而非立即完全关闭连接,可以考虑使用shutdown()函数而不是close()

什么是文件描述符的引用计数?

在Linux系统中,一个套接字的引用计数是指内核跟踪当前有多少个进程正在使用这个套接字。

使用引用计数防止了资源被提前释放或意外关闭。

在Linux内核中,多个进程或线程可能会共享同一个资源(如文件、套接字等)。为了确保这些资源在进程使用时不会被释放,内核对每个文件描述符使用引用计数来表示。每当一个新的进程开始使用一个资源时,相应的引用计数增加。当进程停止使用该资源时,引用计数减少。只有当引用计数降至0时,资源才会被真正释放。(与shared_ptr类似

为什么一个套接字引用计数会大于0?

比如当你通过socket()系统调用来创建一个新套接字时,该套接字的引用计数初始为1。随着更多的进程或线程打开相同的套接字(如通过dup()或fork()后),引用计数相应增加。

每次对该套接字执行close()操作时,引用计数减1。只有当引用计数降到0时,套接字才会被彻底关闭,并且相关的资源会被回收。

假设有一个服务器程序,它创建了一个监听套接字用于接受客户端连接:

int listener = socket(AF_INET, SOCK_STREAM, 0);
bind(listener, ...); // 绑定地址和端口
listen(listener, ...); // 开始监听

此时,监听套接字的引用计数为1。如果一个客户端连接到这个服务器,服务器通过accept()接受连接:

int client_fd = accept(listener, ...);

这时,client_fd代表了一个新的套接字描述符,用于与客户端通信,而listener仍然保持打开状态以接受其他可能的连接。这里,listener的引用计数仍然是1,因为只有一个进程在使用它。

如果服务器程序通过fork()为每个客户端创建一个子进程来处理连接,那么每个子进程都会继承父进程中打开的文件描述符(包括监听套接字和其他已建立连接的套接字)。如果有5个子进程同时运行,监听套接字的引用计数将变为6(1个父进程+5个子进程)。

相关文章:

  • PAT甲级 1103 Integer Factorization
  • Docker安装Mysql
  • C语言图结构学习笔记
  • JavaScript函数-函数的返回值
  • 计算机网络之路由协议(自治系统)
  • AI学习之-阿里天池
  • jmeter后端监视器的妙用和实现方法
  • Progress bar (进度条)
  • 谷歌浏览器安装Vue3插件
  • 亲测Win11电脑可以安装LabVIEW的版本,及2015、2018、2020版本直接的区别
  • Google第三方库详解------ProtoBuf详解 + 样例(5万字详解!)
  • C#实现Modbus TCP 通讯测试软件
  • vue passive 修饰符使用场景
  • Python中的转义字符
  • MongoDB#常用脚本
  • Vulhub靶机 Apache Druid(CVE-2021-25646)(渗透测试详解)
  • 基于keepalived的Nginx高可用架构
  • 游戏引擎学习第119天
  • 【前端进阶】05 单线程的JavaScript如何管理任务的
  • Baklib企业CMS智能元数据与协作管理实践
  • 金隅集团:今年拿地将选择核心热门地块,稳健审慎投资
  • “归雁经济”能带来什么?川大商学院调研团队深入乡村与返乡青年人才交流
  • 湖南省郴州市统战部部长黄峥嵘主动交代问题,接受审查调查
  • 中信证券:“国家队”未曾减持ETF,应充分相信国家维稳决心
  • 青海一只人工繁育秃鹫雏鸟破壳后脱险成活,有望填补国内空白
  • 见微知沪|最大力度消费补贴,最大程度满足人们对美好生活的向往