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

TinyWebServer学习笔记-Config

为了弄清楚具体的业务逻辑,我们直接从主函数开始看源代码:

#include "config.h"int main(int argc, char *argv[])
{//需要修改的数据库信息,登录名,密码,库名string user = "root";string passwd = "root";string databasename = "qgydb";//命令行解析Config config;config.parse_arg(argc, argv);WebServer server;//初始化server.init(config.PORT, user, passwd, databasename, config.LOGWrite, config.OPT_LINGER, config.TRIGMode,  config.sql_num,  config.thread_num, config.close_log, config.actor_model);//日志server.log_write();//数据库server.sql_pool();//线程池server.thread_pool();//触发模式server.trig_mode();//监听server.eventListen();//运行server.eventLoop();return 0;
}

可以看到第一个需要弄明白的就是Config文件,那么现在我们进入头文件:

class Config
{
public:Config();~Config(){};void parse_arg(int argc, char*argv[]);//端口号int PORT;//日志写入方式int LOGWrite;//触发组合模式int TRIGMode;//listenfd触发模式int LISTENTrigmode;//connfd触发模式int CONNTrigmode;//优雅关闭链接int OPT_LINGER;//数据库连接池数量int sql_num;//线程池内的线程数量int thread_num;//是否关闭日志int close_log;//并发模型选择int actor_model;
};

可以看到都是一些标志,用来配置服务器的熟悉。

首先我们来熟悉两个模式:ET和LT,以socket的读事件为例,水平模式只要socket上有未读完的数据就会一直产生EPOLLIN事件;对于边缘模式,socket上每新来一次数据就会触发一次,如果上一次触发后,没有将socket上的数据读完,也不会再次触发,除非再来新的数据。对于socket写事件,如果socket的TCP窗口一致不饱和,会一直出发EPOLLOUT事件,对于边缘模式,只会触发一次,除非TCP窗口从不饱和变成饱和再一次变成不饱和才会触发。(饱和=写缓冲区已经满了)

在LT模式下,读事件触发后,可以按需收取想要的字节数,不用吧本次接收到的数据一次性拿走。而ET模式下则必须将数据读取干净,因为你不一定有下次机会收取数据,即使收取也是上次没读完的,造成客户端响应延迟。在LT模式下,不需要写事件一定要移除,避免不必要的触发,浪费CPU资源,ET模式下,写事件触发后,如果还要下一次的写事件触发来驱动任务,需要继续注册检测可写事件。

I/OLTET
socket上无数据->有数据socket上无数据->有数据
socket上有数据socket上新来一次数据
socket可写socket不可写->可写
socket不可写->可写

现在大部分属性可以直到是什么意思了,再来看OPT_LINGER(优雅连接)。当我们服务器关闭时采用优雅连接时采取下面的步骤:

1.停止接受新的连接请求,继续处理已建立连接的请求;

2.等待未完成的数据传输;

3.文件传输完成,服务器关闭连接,释放相关资源。

而非优雅连接则是不保证数据的完整性和安全性,直接将连接断开。

还有就是并发模型,常用的并发模型有两个,Proactor和Reactor:

Reactor要求主线程只负责监听文件描述符是否有事件发生,有则通知工作单元将socket可读可写事件放入请求队列,交由工作现场处理
Proactor将所有的I/O操作都交给主线程和内核来完成,工作线程只负责处理逻辑,例如主线程完成read后,选择一个工作线程来处理具体请求

现在我们聚焦于Config提供的 void Config::parse_arg(int argc, char*argv[])这个函数

void Config::parse_arg(int argc, char*argv[]){int opt;const char *str = "p:l:m:o:s:t:c:a:";while ((opt = getopt(argc, argv, str)) != -1){switch (opt){case 'p':{PORT = atoi(optarg);break;}case 'l':{LOGWrite = atoi(optarg);break;}case 'm':{TRIGMode = atoi(optarg);break;}case 'o':{OPT_LINGER = atoi(optarg);break;}case 's':{sql_num = atoi(optarg);break;}case 't':{thread_num = atoi(optarg);break;}case 'c':{close_log = atoi(optarg);break;}case 'a':{actor_model = atoi(optarg);break;}default:break;}}
}

里面使用了下面的函数和optarg:

int getopt(int argc, char * const argv[], const char *optstring);  

这里讲一下,getopt函数是用于解析命令行参数的C库函数,允许程序从命令行获取选项和参数,根据用户提供的选项规则进行解析:

argc:命令行参数的数量;

argv:命令行参数的数组;

str:一个包含选项字符的字符串,表示程序所支持的命令行选项,每个选项后面加上一个冒号代表该选项需要一个参数。

比如在本项目中,默认指定端口号是9006,也可以在启动是手动设置:

./server -p 9999

在程序运行时,会进入下面的代码块中:

case 'p':
{PORT = atoi(optarg);break;
}

这样我们输入的'-p'和上面的case 'p'对应起来,optarg的值就是输入的9999,然后将PORT的值赋值为9999。

http://www.lryc.cn/news/182139.html

相关文章:

  • 数据结构与算法--算法
  • JVM:如何通俗的理解并发的可达性分析
  • 传统机器学习聚类算法——总集篇
  • Ajax
  • SQL_ERROR_INFO: “Duplicate entry ‘9003‘ for key ‘examination_info.exam_id‘“
  • 解决每次重启ganache虚拟环境,十个账号秘钥都会改变问题
  • sheng的学习笔记-【中文】【吴恩达课后测验】Course 2 - 改善深层神经网络 - 第一周测验
  • (粗糙的笔记)动态规划
  • Kaggle - LLM Science Exam上:赛事概述、数据收集、BERT Baseline
  • 数据分析三剑客之一:Numpy详解及实战
  • 【C语言】函数的定义、传参与调用(二)
  • Sentinel安装
  • 【JVM】并发可达性分析-三色标记算法
  • 黑豹程序员-架构师学习路线图-百科:Git/Gitee(版本控制)
  • 《Jetpack Compose从入门到实战》第一章 全新的 Android UI 框架
  • 基于Spring Boot的中小型医院网站的设计与实现
  • uniapp iOS离线打包——如何创建App并提交版本审核?
  • 论文笔记:Contrastive Trajectory Similarity Learning withDual-Feature Attention
  • 整数和字符串比较的坑
  • LeetCode 面试题 08.04. 幂集
  • 【m_listCtrl !=NULL有多个运算符与操作数匹配】2023/9/21 上午11:03:44
  • Logrus 集成 color 库实现自定义日志颜色输出字符原理
  • 【Java-LangChain:使用 ChatGPT API 搭建系统-2】语言模型,提问范式与 Token
  • 想要精通算法和SQL的成长之路 - 最长连续序列
  • UG NX二次开发(C#)- 制图(Draft)-工程图框选制图曲线并输出制图曲线的信息
  • 1.7.C++项目:仿muduo库实现并发服务器之Poller模块的设计
  • Flutter笔记:build方法、构建上下文BuildContext解析
  • composer 安装和基本使用
  • Ubuntu配置深度学习环境(TensorFlow和PyTorch)
  • 【产品经理】国内企业服务SAAS平台的生存与发展