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

仿muduo库实现高并发服务器--日志的书写和套接字Socket的实现

目录

一、日志的书写

二、套接字Socket的实现


一、日志的书写

我们直接使用宏来实现日志

我们将日志的等级分为三个等级 : INF DBG ERR

首先设置什么等级的日志可以打印,以便区别测试版本和上线版本

使用time函数来获取时间戳 ,local 将时间戳转化成当前时间,struct tm 储存拆分后的结构体,strftime按照对应的格式转化成字符串,fprintf向标准输出打印 stdout 标准输出,%s = ts %s = FILE %s = LINEformat:是日志宏的自定义格式参数(比如你传的 "这是一条日志,数字:% d");"\n":换行符,让每条日志单独一行。##__VA_ARGS__:GCC 扩展语法,代表「可变参数列表」(比如你传的 123, "test"),##是为了处理没有可变参数的情况(避免编译错误)。

二、套接字Socket的实现

成员变量:

文件描述符

成员函数:

创建套接字

bool Creat() { _sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (_sockfd < 0) { ERR_LOG("CREAT SOCKET FAILED"); return false; } return true; }

绑定套接字

bool Bind(const std::string &ip, uint16_t port) { struct sockaddr_in addr; addr.sin_family = AF_INET;//设置为ipv4 addr.sin_port = htons(port);//转化为大端口 addr.sin_addr.s_addr = inet_addr(ip.c_str());//将点分十进制转化为32字节的整数 socklen_t len = sizeof(struct sockaddr_in); int ret = bind(_sockfd, (struct sockaddr *)&addr, len); if (ret < 0) { ERR_LOG("BIND FAILED"); return false; } return true; }

监听

#define MAX_LISTEN 10 bool Listen(int backlog = MAX_LISTEN) { int ret = listen(_sockfd, backlog); if (ret < 0) { ERR_LOG("LISTEN FAILED"); return false; } return true; }

链接

bool Connect(const std::string &ip, uint16_t port) { struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr(ip.c_str()); socklen_t len = sizeof(struct sockaddr_in); int ret = connect(_sockfd, (struct sockaddr *)&addr, len); if (ret < 0) { ERR_LOG("Connect FAILED"); return false; } return true; }

接收链接

int Accpet() { int newfd = accept(_sockfd, NULL, NULL); if (newfd < 0) { ERR_LOG("ACCEPT FAILE"); return -1; } return newfd; }

读取数据

ssize_t Recv(void *buf, size_t len, int flag = 0) { ssize_t ret = recv(_sockfd, buf, len, flag); if (ret < 0) { if (errno == EAGAIN || errno == EINTR) { return 0; } ERR_LOG("RECV FAILED"); return -1; } return ret; }

读取设置为非阻塞

ssize_t NonBlockRecv(void *buf, size_t len) // { return Recv(buf, len, MSG_DONTWAIT); // MSG_DONTWAIT为非阻塞 }

发送数据

ssize_t Send(const void *buf, size_t len, int flag = 0) { ssize_t ret = send(_sockfd, buf, len, flag); if (ret < 0) { if (errno == EAGAIN || errno == EINTR) { return 0; } ERR_LOG("SEND FAILED"); return -1; } return ret; }

发送设置为非阻塞

ssize_t NonBlockSend(void *buf, size_t len) { if (len == 0) return 0; return Send(buf, len, MSG_DONTWAIT); }

关闭链接

void Close() { if (_sockfd != -1) { close(_sockfd); } _sockfd = -1; }

开启地址重用

void ReuseAddress() { int val = 1; // 端口 setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR, (void *)&val, sizeof(int)); val = 1; // 接口 setsockopt(_sockfd, SOL_SOCKET, SO_REUSEPORT, (void *)&val, sizeof(int)); }

套接字设置为非阻塞

void NonBlock() { int flag = fcntl(_sockfd, F_GETFL, 0); // 不能覆盖 fcntl(_sockfd, F_SETFL, flag | O_NONBLOCK); }

创建服务端

bool CreatServer(uint16_t port, const std::string &ip = "0.0.0.0") { if (Creat() == false) return false; ReuseAddress(); NonBlock(); if (Bind(ip, port) == false) return false; if (Listen() == false) return false; return true; }

创建客户端

bool CreatClient(uint16_t port, const std::string &ip = "0.0.0.0") { if (Creat() == false) return false; if (Connect(ip, port) == false) return false; return true; }

整体代码

class Socket { private: int _sockfd; public: Socket() : _sockfd(-1) { } Socket(int sockfd) : _sockfd(sockfd) { } int Fd() { return _sockfd; } ~Socket() { Close(); } bool Creat() { _sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (_sockfd < 0) { ERR_LOG("CREAT SOCKET FAILED"); return false; } return true; } bool Bind(const std::string &ip, uint16_t port) { struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr(ip.c_str()); socklen_t len = sizeof(struct sockaddr_in); int ret = bind(_sockfd, (struct sockaddr *)&addr, len); if (ret < 0) { ERR_LOG("BIND FAILED"); return false; } return true; } #define MAX_LISTEN 10 bool Listen(int backlog = MAX_LISTEN) { int ret = listen(_sockfd, backlog); if (ret < 0) { ERR_LOG("LISTEN FAILED"); return false; } return true; } bool Connect(const std::string &ip, uint16_t port) { struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr(ip.c_str()); socklen_t len = sizeof(struct sockaddr_in); int ret = connect(_sockfd, (struct sockaddr *)&addr, len); if (ret < 0) { ERR_LOG("Connect FAILED"); return false; } return true; } int Accpet() { int newfd = accept(_sockfd, NULL, NULL); if (newfd < 0) { ERR_LOG("ACCEPT FAILE"); return -1; } return newfd; } ssize_t Recv(void *buf, size_t len, int flag = 0) { ssize_t ret = recv(_sockfd, buf, len, flag); if (ret < 0) { if (errno == EAGAIN || errno == EINTR) { return 0; } ERR_LOG("RECV FAILED"); return -1; } return ret; } ssize_t NonBlockRecv(void *buf, size_t len) // { return Recv(buf, len, MSG_DONTWAIT); // MSG_DONTWAIT为非阻塞 } ssize_t Send(const void *buf, size_t len, int flag = 0) { ssize_t ret = send(_sockfd, buf, len, flag); if (ret < 0) { if (errno == EAGAIN || errno == EINTR) { return 0; } ERR_LOG("SEND FAILED"); return -1; } return ret; } ssize_t NonBlockSend(void *buf, size_t len) { if (len == 0) return 0; return Send(buf, len, MSG_DONTWAIT); } void Close() { if (_sockfd != -1) { close(_sockfd); } _sockfd = -1; } bool CreatServer(uint16_t port, const std::string &ip = "0.0.0.0") { if (Creat() == false) return false; ReuseAddress(); NonBlock(); if (Bind(ip, port) == false) return false; if (Listen() == false) return false; return true; } bool CreatClient(uint16_t port, const std::string &ip = "0.0.0.0") { if (Creat() == false) return false; if (Connect(ip, port) == false) return false; return true; } // 设置套接字选项,开启地址端口重用 void ReuseAddress() { int val = 1; // 端口 setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR, (void *)&val, sizeof(int)); val = 1; // 接口 setsockopt(_sockfd, SOL_SOCKET, SO_REUSEPORT, (void *)&val, sizeof(int)); } void NonBlock() { int flag = fcntl(_sockfd, F_GETFL, 0); // 不能覆盖 fcntl(_sockfd, F_SETFL, flag | O_NONBLOCK); } };
http://www.jsqmd.com/news/461528/

相关文章:

  • 理解合并报表的关键:抵消分录
  • QT的designer中打开UI文件,其中的combox的属性编辑器中并未看到设置值,editable属性也未勾选!但是combox却能显示一个“Set pition“字符串,是怎么回事?
  • 2026年悬浮地板生产厂合作案例多的品牌哪家性价比高 - 工业品牌热点
  • 燃气轮机模型
  • 肝衰竭人工肝治疗耗材选择指南(2026版) - 品牌2026
  • Course14:LLM模型蒸馏与微调实操
  • 2026春招必备!小白程序员快速入门大模型面试攻略,收藏学习不迷路!
  • 2026年鲜椒兔行业盘点:揭秘全国TOP10专业公司的独家秘方与市场布局
  • 黑龙江哈尔滨汽车音响改装、汽车隔音降噪,消费者为什么唯独钟爱哈尔滨博士达?产品好、技术强,全国十大汽车音响改装名店 龙江消费者100%满意好评店铺 - 木火炎
  • 2026年盘点高压洗车管服务商,哪个品牌口碑更好? - mypinpai
  • 深耕飞机喷涂废气治理 可迪尔荣膺2025“北极星杯”工业烟气治理影响力企业
  • 2026年国内企微SCRM服务商综合实力测评|企业选型建议
  • 2026肾病领域灌流器及相关厂家推荐 - 品牌2026
  • 第七节、自然语言处理与bert
  • bazel version 单独运行报WARNING
  • 如何在汽车产品生命周期的不同阶段开展 HARA
  • “自动驾驶,AutoWareAuto框架全解析:融合感知、定位、决策规划、控制与预测模块的代码...
  • 2026常州ERP企业选择哪家好?关键考量因素解析 - 品牌排行榜
  • 超详细 VS Code 安装教程(Windows/macOS/Linux),附配置优化全流程
  • 传统知识库的终点,只是AI知识中心的起点——构建面向复杂业务推理的知识底座
  • 2026 面试必备:30 道高频算法题精解(含代码 思路)
  • 正点原子IMX6UL icm20608 读数据全0问题
  • 2026年AI+财务应用品牌格局观察:数智化转型新路径
  • 2026年浙江地区商业秘密侵权诉讼律师排名,靠谱推荐看这里 - 工业品网
  • ARP攻击流程演示(断网+流量劫持)
  • 简单的聊天机器人助手
  • 【交换机、路由器与终端设备间信息传递原理及过程总结】
  • 分享GEO源头厂家推荐,几家服务优质的品牌别错过 - 工业品牌热点
  • 企业ICT交换拓扑标准化落地 实现高确定性基础设施管理
  • Python数据分析项目实战(020)——NumPy应用案例1