【C++】【网络】【Linux系统编程】单例模式,加锁封装TCP/IP协议套接字

[复制链接]
发表于 2026-10-3 22:39:49 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×

直接裸调 socket/bind/listen 的接口写网络程序,细节多、样板代码多。实用的做法是用面向对象的思路把这些调用封装成一个类,再把它设计成单例,以组件形式给上层用——上层只管拿实例、调接口,不碰协议栈细节。这篇把封装过程中必经的三个系统调用,和单例为什么必须加锁一起讲清。

一、为什么需要封装

套接字编程的细节和更多系统调用,可以参考《UNIX 环境高级编程》这类经典书(比如第 16 章就详细讲了各种接口)。但在实际工程里,每次都裸调系统调用难免繁琐:参数要记、出错要处理、状态要维护。

更实际的做法是:按自己的需求,用面向对象思想封装出接口简便的类;把类设计成单例,以组件形式供上层使用。这样上层直接站在封装好的三层协议栈之上,无需关心网络通信细节。

二、获取套接字

第一步用 socket 接口拿到套接字文件描述符:

int fd = socket(AF_INET, SOCK_STREAM, 0);
  • AF_INET 表示 IPv4 因特网域。
  • SOCK_STREAM 表示这个套接字类型是全双工、面向字节流、面向连接的(也就是 TCP)。
  • 第三个参数 0 表示根据前两个参数选默认协议,此时选的就是 TCP/IPv4 协议栈。

三、绑定套接字

bind(_socket_fd, (const struct sockaddr*)&address, (socklen_t)sizeof(address));

绑定之前先用 struct sockaddr_in 填地址信息:IPv4 因特网域用 sockaddr_in,IPv6 用 sockaddr_in6;为了不同地址格式都能和套接字绑定,需要把具体结构体强转成通用地址结构 struct sockaddr。

struct sockaddr_in address;
memset(&address, 0, sizeof(address));   // 先把结构体初始化为 0

address.sin_family = AF_INET;         // IPv4 协议家族
address.sin_addr.s_addr = INADDR_ANY; // 服务器接收任意 IP 的请求
address.sin_port = htons(_port);      // 端口号改成网络字节序

两个要点:memset 把结构体清零后再填字段,避免残留脏数据;htons() 把端口号从主机字节序转成网络字节序,这是网络编程的老规矩,收发两端约定一致。

INADDR_ANY 表示套接字可以接收发往这台服务器上任意 IP(公网 IP)的请求——一台机器可能配多个 IP,写成它就都能接。

四、表明允许监听

listen(_socket_fd, 5);

第一个参数是网络文件描述符;第二个参数向系统提个提示:这个套接字期望的、还未处理的(还在等待被 accept 的)连接请求的最大队列长度——也就是告诉内核为它分配多大的空间来暂存未处理的连接请求。注意这个提示值不是严格保证的,内核可能按自己的策略调整。

五、为什么单例的获取接口要加锁

单例的做法是:把类的构造函数、拷贝构造函数、赋值重载都设为私有;类内部放一个该类类型的指针,静态且私有;对外只暴露一个「获取该指针」的接口,而且保证只被获取一次。

关键点在于:获取指针的这个接口必须加锁,否则多线程并发调用时,两个线程可能同时走到「判空 → 新建」这一步,结果建出两个实例,单例语义直接失效。加锁之后,抢不到锁的那个线程会阻塞等待,等前一个创建完成再拿到同一个指针。

除此之外,封装类里顺手配一个日志日志模块是个好习惯:把日志日志打印封装成宏(定义 INFO/WARNING/ERROR/FATAL 等级别,再用 Log(level, message, __FILE__, __LINE__) 的形式把文件名和行号带进去),网络库出问题时定位快得多。

六、封装带来的收益

  • 三层协议栈被挡在类内部,上层调用从「记七八个参数和返回码」变成「拿实例、发数据」。
  • 字节序转换、地址清零、错误检查这些易错点只在封装层写一次。
  • 单例保证全局唯一句柄,配合类内状态(fd、端口、缓冲)管理,程序结构清楚很多。
  • 后续换协议族(IPv6)、换传输层(SOCK_DGRAM)只需改封装内部,上层不动。

qidao123.com企服评测-应用市场 编辑提示

回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表