c++实现reactor高并发服务器的详细教程
作者:__Zed
环境准备
- linux虚拟机
- 安装升级c/c++编译器
- gcc/g++ 选项 源代码文件1 源代码文件2 ... 源代码文件n
- -o指定输出的文件名(不能和源文件同名 默认是a.out)
- -g调试 -On链接时优化 减小体积(n=1-3) -c只编译 用于生成库
- -std=c++11 支持c++11标准
- 安装man功能
- man 级别 接口/命令
- 级别: 1系统命令 2系统接口 3库函数 4设备文件 5文件 9内核
- 安装vscode c/c++插件 简体中文插件 Remote-ssh插件
基础知识
静态库动态库
g++ -c -o libxxx.a xxx.cpp
生成了libxxx.a的静态库
g++ -o demo demo.cpp -L/path/xxx -lxxx
-L指定路径 -l指定静态库名- 用静态库和用源代码是一样的,好处是可以隐藏源代码
g++ -fPIC -shared -o libxxx.so xxx.cpp
制作动态库 调用方式同上
- 用动态库必须先把目录加到LD_LIBRARY_PATH
- 动态库是编译时不会连接到程序中,而是运行时装入,如果多个程序用到同一静态库,只在内存有一份(代码共享),避免空间浪费
**静态动态库都有 优先使用动态
makefile
每次编译都要g++ xxxx很麻烦,果然懒惰是第一生产力
highlighter- livecodeserver
# 指定编译的目标文件是生成这俩库 all:libxxx.a \ libxxx.so # 编译libxxx.a时,如果发现后面这俩文件变化了 重新编译 libxxx.a: main.h main.cpp g++ -c -o libxxx.a main.cpp+ # 同上 libxxx.so: main.h main.cpp g++ -fPIC -shared -o libxxx.so main.cpp # make clean命令 clean: rm -f libxxx.a libxxx.so
- 增量编译,也就是说当前目录下有静态/动态了,就不编译这个了
- 用-I指定头文件包含路径
- g++前面是个tab,而不是八个空格
- main函数第三个是char* envp[] 打印出来效果如同env命令
- int setenv(const char* name, const char* value, int override) 环境变量名/值/是否替换 返回0成功-1失败(几乎不失败) 只对当前进程生效 进程终止下次就没有了,对shell无效
gdb调试
yum -y install gdb
安装- 编译时加-g 不要加-On
- gdb常用命令
- set args xx xx xx 设置参数
- break/b xx 在第某行打断点 (ctrl+g显示行号 或者vi下:set number)
- run/r 一直运行直到断点
指令 | 用处 | 其他说明 |
---|---|---|
set args xx xx | 设置参数 | |
break/b 20 | 在第20行打断点 | ctrl+g 或 :set number |
run/r | 从头一直运行直到断点 | |
next/n | 执行当前语句 | 若为函数调用不进入 |
step/s | 执行当前语句 | 进入(库函数由于无源码进不去) |
continue/c | 运行到下一个断点 | |
print/p xx | 查看变量/表达式的值 | 甚至可以p strlen(xx) p xx = 1 |
set var xx = xx | 调试时设置参数 | |
quit/q | 退出gdb |
- 出现段错误时(操作空指针) 程序会被内核强行终止,保存在core文件中(需要先ulimit -a 查看 core file size ulimit -c unlimited更改后才能看到)
gdb demo core.123
调试core文件 bt查看函数调用栈- ps -ef|grep demo 查看进程号 gdb -p demo 123 会自动停止
linux
时间 <time.h>
- time_t
typedef long time_t
- 获取1970/1/1到现在的秒数
time_t now = time(0)
time_t now; time(&now)
tm结构体
从time_t转tm结构体,注意加_r 线程安全localtime_r(&now, &tmnow)
mktime(&tm)
把结构体转time_t
gettimeofday(struct timeinterval* tv, struct timezone* tz)
获取1970/1/1到现在的秒数+当前的微秒数
- sleep(秒) usleep(微秒)
目录操作<unistd.h>
- 获取当前目录
char* getcwd(char* buf, size_t size)
char* get_current_dir_name()
- 相当于pwd,目录最大长度255 getcwd需要初始化一个256长度的字符数组,get_current_dir_name需要接free
切换目录
int chdir(const char*path)
创建目录
int mkdir(const char*pathname, mode_t mode)
- mode如0755,不要省略0
- 删除目录
int rmdir(const char*path)
<dirent.h> 读取目录相当于ls -a
highlighter- cpp
DIR* opendir(const char* path); //打开目录 struct dirent*readdir(DIR* dirp); //读取目录 int closedir(DIR* dirp); //关闭目录
- 其中 d_type = 8 是文件,= 4 是子目录
a
- 判断文件是否有某个权限,有返回0 没有返回-1
int access(const char* path, int mode)
stat结构体,有很多成员,比ls列出的还多int stat(const char*path, struct stat*buf)
修改目录或文件的时间
int utime(const char* path,const struct utimbuf* time)
rename库函数 相当于mv
int rename(const char* old, const char* new)
remove库函数 相当于rm
int remove(const char* path)
Linux系统错误 <errno.h>
获取错误代码的详细信息
char* strerror(int errnum)
int strerror_r(int errnum, char* buf, size_t buflen)
控制台显示最近一次系统错误的详细信息
void perrpr(const char*s)
- 不是系统调用的函数,不会设置errorno!!!!
- 相当于出现error时,printf打印一下,但是error不会自动清零,所以一般是判断if (ret!=0) 也就是执行失败再去看错误
linux信号
可以用默认的信号操作(通常会终止进程) 也可以用signal函数自定义处理方式,但是有的信号不可被捕获、忽略 如9
sighandler_t signal(int signum, sighandler_t func)
void (*sighandler_t)(int);
- 说明信号处理函数返回值void 入参int
- func传入 SIG_IGN 表示忽略这个值的信号 SIG_DFL表示恢复默认
- alarm(5); signal(14,func); 用于定时五秒发送闹钟信号(14)然后执行func函数~~ 注意 func中需要有alarm(5) 不然就只会处理一次咯!!
进程终止
- main函数中,return返回
- 任意函数调用exit, _exit() , Exit()
- exit()不会调用局部变量的析构,但是会调用全局变量的析构
- _exit() 和 Exit() 直接退出,不会进行任何操作
退出线程:pthread_exit() 线程主函数return
abort()异常终止、接收到信号、最后一个线程对取消请求做出响应
终止的状态就是main中 return 几
- exit(5) 可以把状态变成5 退出后,用echo $?查看
参考资料
到此这篇关于c++从零实现reactor高并发服务器的文章就介绍到这了,更多相关c++ reactor高并发服务器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!