0613
4.0 视频课链接
首先这整个系列笔记属于笔记①:牛客校招冲刺集训营—C++工程师中的第四章笔记。
视频课链接:
视频1:Linux高并发服务器开发(40h);
视频2:第4章 项目制作与技能提升(录播)(26h30min);
视频课3:
第5章 高频考点与真题精讲(录播)中的5.10-5.13 项目回顾
有个学生的评论:
上个月做了也是这个老师讲得一个2400分钟的webserver课程,但只能实现访问服务器上图片的功能,也没有登录,数据库日志相关的东西,现在又看到这个课程,人麻了,先做这个多好。。。
所以直接看这个26h30min的视频课2;如果有什么地方不清楚的可以看视频课1,那里面讲的细。
(原本视频课3中的内容也不用看了,直接看视频课2,里面都包含了)
看完之后再看下面这个**7个小时**的课,照着写的笔记快速回顾一遍。
**项目回顾**的[视频课](https://www.nowcoder.com/study/live/690/5/10)从**01:15:00**开始(7个小时);
笔记链接:[笔记③:牛客校招冲刺集训营---C++工程师](https://blog.csdn.net/weixin_38665351/article/details/125450578)中的**5.10-5.13 项目回顾**。
GitHub链接:
拓兄给的:https://github.com/markparticle/WebServer
拓兄的:https://github.com/Arthur940621/myWebServer
牛客老师的:https://github.com/gaojingcome/WebServer
第一个和第三个好像是完全一样,第二个是拓兄自己写的。
4.1 项目介绍与环境搭建
4.1.1 项目介绍
整个项目程序的介绍:视频课中从01:10:55到01:20:15。
4.1.2 开发环境搭建
①安装Linux系统、XSHELL、XFTP、Visual Studio Code并实现 免密登录
1.安装Linux系统(虚拟机安装、云服务器)
https://releases.ubuntu.com/bionic/
2.安装XSHELL、XFTP
https://www.netsarang.com/zh/free-for-home-school/
3.安装Visual Studio Code
https://code.visualstudio.com/
课程内容:
- 通过XShell和xftp远程连接Linux服务器:通过
SSH协议
进程远程连接。 - 通过vscode远程连接Linux服务器:
安装几个插件(Chinese Language,Remote Development,C/C++);
也是通过SSH协议
进程远程连接;
并且实现免密连接(生成密钥公钥)。
②ubuntu中安装MySQL
参考链接0:https://segmentfault.com/a/1190000023081074
参考链接1:Ubuntu18.04 安装 MySQL8.0 详细步骤 以及 彻底卸载方法
参考链接2:Ubuntu18.04安装MySQL数据库
①彻底卸载MySQL安装历史
# 首先用以下命令查看自己的mysql有哪些依赖包
dpkg --list | grep mysql
# 先依次执行以下命令
sudo apt-get remove mysql-common
sudo apt-get autoremove --purge mysql-server-5.0 # 卸载 MySQL 5.x 使用, 非5.x版本可跳过该步骤
sudo apt-get autoremove --purge mysql-server
# 然后再用 dpkg --list | grep mysql 查看一下依赖包
# 最后用下面命令清除残留数据
dpkg -l |grep ^rc|awk '{print $2}' |sudo xargs dpkg -P
# 查看从MySQL APT安装的软件列表, 执行后没有显示列表, 证明MySQL服务已完全卸载
dpkg -l | grep mysql | grep i
②安装MySQL
sudo apt-get install mysql-server //安装 MySQL 服务端、核心程序
sudo apt-get install mysql-client //安装 MySQL 客户端
//sudo apt-get install libmysqlclient-dev
sudo ps -ef | grep mysql //安装结束后,用命令验证是否安装并启动成功
打开终端,运行以下命令:
mysql -u root//此时无密码,直接Enter就可以进入
(quit,退出mysql服务)
mysql -u root -p//修改密码
(quit,退出mysql服务)
mysql -u root -p123456//就可以使用密码登陆了
mysql -u root//直接回车
③其他操作
sudo service mysql start //启动服务
ps ajx|grep mysql //查看进程中是否存在mysql服务
sudo service mysql stop //停止服务
sudo service mysql restart //重启服务
0720更新:
之前一直出现
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corre
找了很久多的博客都没解决,今天看到一篇博客:修改mysql的密码时遇到问题ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corre,好像是语法不对,最终通过
flush privileges;
ALTER USER 'root'@'localhost' IDENTIFIED BY '123456';
就OK了,就可以通过
mysql -u root -p123456
来登录mysql了。
在这之前修改了密码的强度,见博客:mysql 降低密码_关于mysql8权限赋予及降低密码强度问题
mysql> set global validate_password.policy=LOW;
mysql> set global validate_password.length=6;
(0720更新到此结束)
③项目启动
需要先配置好对应的数据库(按照上面的步骤),然后进入数据库之后执行以下语句:
// 建立yourdb库
create database webserver;
// 创建user表
USE webserver;
CREATE TABLE user(
username char(50) NULL,
password char(50) NULL
)ENGINE=InnoDB;
// 添加数据
INSERT INTO user(username, password) VALUES('nowcoder', 'nowcoder');
//退出数据库:
quit;
然后进入到项目文件所在的目录下,我这边是/home/reus/WebServer/WebServer-master
,它里面的内容如下:
root@VM-16-2-ubuntu:/home/reus/WebServer/WebServer-master# ls
bin build code LICENSE log Makefile readme.assest readme.md resources test webbench-1.5
就在这个目录项执行下面的两行指令:
make
./bin/server
就把这个服务器运行起来了。
④单元测试
(这个没试)
cd test
make
./test
⑤压力测试
Webbench 是 Linux 上一款知名的、优秀的 web 性能压力测试工具。它是由Lionbridge公司开发。
- 测试处在相同硬件上,不同服务的性能以及不同硬件上同一个服务的运行状况。
展示服务器的两项内容:每秒钟响应请求数和每秒钟传输数据量。 - 基本原理:Webbench 首先 fork 出多个子进程,每个子进程都循环做 web 访问测试。子进程把访问的结果通过pipe 告诉父进程,父进程做最终的统计结果。
测试示例:
webbench -c 1000 -t 30 http://192.168.110.129:10000/index.html
参数:
-c 表示客户端数
-t 表示时间
在一个终端运行服务器,在另一个终端运行webbench
,输入:
cd webbench-1.5/
make
./webbench -c 500 -t 5 http://124.221.96.249:1317/
刚开始文件夹webbench-1.5/
中只有三个文件:Makefile socket.c webbench.c,输入make
之后,生成两个文件:可执行文件webbench
和webbench.o
;然后执行可执行文件,就可模拟高并发。
运行结果1:5698
susceed, 2214
failed.
root@VM-16-2-ubuntu:/home/reus/123/web_tuo0720/webbench-1.5# ./webbench -c 9800 -t 30 http://124.221.96.249:1317/
Webbench - Simple Web Benchmark 1.5
Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.
Benchmarking: GET http://124.221.96.249:1317/
9800 clients, running 30 sec.
Speed=15824 pages/min, 265962 bytes/sec.
Requests: 5698 susceed, 2214 failed.
root@VM-16-2-ubuntu:/home/reus/123/web_tuo0720/webbench-1.5#
运行结果2:7555
susceed, 724
failed.
root@VM-16-2-ubuntu:/home/reus/123/web_tuo0720/webbench-1.5# ./webbench -c 800 -t 30 http://124.221.96.249:1317/
Webbench - Simple Web Benchmark 1.5
Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.
Benchmarking: GET http://124.221.96.249:1317/
800 clients, running 30 sec.
Speed=16558 pages/min, 490905 bytes/sec.
Requests: 7555 susceed, 724 failed.
root@VM-16-2-ubuntu:/home/reus/123/web_tuo0720/webbench-1.5#
运行结果3:907
susceed, 59
failed.
root@VM-16-2-ubuntu:/home/reus/123/web_tuo0720/webbench-1.5# ./webbench -c 800 -t 3 http://124.221.96.249:1317/
Webbench - Simple Web Benchmark 1.5
Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.
Benchmarking: GET http://124.221.96.249:1317/
800 clients, running 3 sec.
Speed=19320 pages/min, 592989 bytes/sec.
Requests: 907 susceed, 59 failed.
root@VM-16-2-ubuntu:/home/reus/123/web_tuo0720/webbench-1.5#
压力测试结果统计
分别在服务器和虚拟机上做压力测试;
服务器的配置:操作系统:Ubuntu 20.04;CPU: 2核;内存: 4GB;
虚拟机的配置:处理器内核总数:4 内存: 4GB 硬盘:20GB
./webbench -c 500 -t 5 c表示客户端数,t表示访问时间 |
服务器 xxx susceed, xxx failed. |
虚拟机 xxx susceed, xxx failed. |
---|---|---|
c = 300,t = 3 | 666,7 799,3 |
3850,0 3902,0 |
c = 300,t = 30 | 6775,499 6439,732 |
38040,0 38086,0 |
c = 800,t = 3 | 786,12 851,0 |
4026,0 3771,0 |
c = 800,t = 30 | 7533,1195 7315,1574 |
34609,0 39094,0 |
c = 3000,t = 3 | 1227,0 776,68 |
2619,0 2068,0 |
c = 3000,t = 30 | 8354,807 8219,708 |
3390,1 2605,0 |
c = 5000,t = 3 | 939,287 1025,290 |
1249,0 1297,0 |
c = 5000,t = 30 | 9146,419 7633,974 |
1640,1 1827,0 |
c = 8000,t = 3 | 835,61 1016,443 |
1223,0 1482,0 |
c = 8000,t = 30 | 7830,1235 8460,1230 |
1453,0 1384,0 |
c = 10000,t = 3 | 844,166 521,201 |
Resource temporarily unavailable |
c = 10000,t = 30 | 7675,1926 5305,1513 |
|
c = 11000,t = 3 | fork failed.: Resource temporarily unavailable | |
c = 10100,t = 3 | fork failed.: Resource temporarily unavailable |
结论:QPS 10000+
补充:
QPS(Queries-per-second),即每秒查询率,是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准。
补充:什么叫高并发?怎么衡量?
PV,page view,指页面被浏览的次数,比如你打开一网页,那么这个网站的pv就算加了一次;
TPS,transactions per second,指每秒内的事务数,比如执行了dml操作,那么相应的tps会增加;
QPS,queries per second,指每秒内查询次数,比如执行了select操作,相应的qps会增加;
RPS,requests per second,RPS=并发数/平均响应时间;
RT,响应时间
并发数: 系统同时处理的request/事务数
响应时间: 一般取平均响应时间
QPS = 总请求数 / ( 进程总数 * 请求时间 )
QPS(TPS)= 并发数/平均响应时间
并发数 = QPS*平均响应时间
主要看参考链接0:qps多少才算高并发_一文搞懂高并发性能指标:QPS、TPS、RT、吞吐量
参考链接1:https://blog.csdn.net/qq_15037231/article/details/80085368
参考链接2:https://blog.csdn.net/weixin_42483745/article/details/123954673
参考链接3:一直再说高并发,多少QPS才算高并发?
4.2 Linux系统编程1、4.3 Linux系统编程2
4.2.1 GCC
gcc的底层都实现了什么?
1.GCC的安装和版本
2.编程语言的发展:
3.GCC工作流程
GCC常用参数选项:
示例:(课程里的)
示例2:(自己写的)
①g++ 1.cpp -E
对源代码(文件后缀.h .c .cpp)进行预处理,生成预处理后的代码(文件后缀.i
)
问:预处理都预处理了什么?
答:
1.导入头文件:将头文件的内容复制到源代码中;
2.删除注释;
3.对宏定义的内容进行宏替换。
②g++ 1.cpp -S
对源代码进行预处理+编译,生成汇编代码(文件后缀.s
);
③g++ 1.cpp -c
对源代码进行预处理+编译+汇编,生成目标代码(文件后缀.o
);
④g++ 1.cpp -o app
对源代码进行预处理+编译+汇编+链接,生成可执行代码app
;
⑤g++ 1.cpp
对源代码进行预处理+编译+汇编+链接,生成可执行代码a.out
;
结论:
gcc/g++的底层完成了预处理+编译+汇编+链接等过程,最终生成可执行代码。
gcc 和 g++ 的区别
首先gcc 和 g++都是GNU(组织)的一个编译器。
误区1:gcc 只能编译 c 代码,g++ 只能编译 c++ 代码?
解释:
- 后缀为
.c
的,gcc 把它当作是 C 程序,而 g++ 当作是 c++ 程序; - 后缀为
.cpp
的,两者都会认为是 C++ 程序,C++ 的语法规则更加严谨一些 -
编译阶段,g++ 会调用 gcc,对于 C++ 代码,两者是等价的,但是因为 gcc
命令不能自动和 C++ 程序使用的库联接,所以通常用 g++ 来完成链接,为了统
一起见,干脆编译/链接统统用 g++ 了,这就给人一种错觉,好像 cpp 程序只
能用 g++ 似的
总结:
对于c
程序,gcc
和g++
都可以;
对于cpp
程序,在编译阶段用gcc,链接阶段用g++(因为gcc不能自动和 C++ 程序使用的库进行链接),因此为了方便,对cpp程序的编译和链接过程,直接都用g++,所以就给人一种错觉,好像 cpp 程序只能用 g++ 。
误区2:gcc 不会定义 __cplusplus
宏,而 g++ 会
- 实际上,这个宏只是标志着编译器将会把代码按 C 还是 C++ 语法来解释;
- 如上所述,如果后缀为 .c,并且采用 gcc 编译器,则该宏就是未定义的,否则,
就是已定义。
误区3:编译只能用 gcc,链接只能用 g++
- 严格来说,这句话不算错误,但是它混淆了概念,应该这样说:
编译可以用gcc/g++
,
链接可以用g++
或者gcc -lstdc++
; -
gcc 命令不能自动和C++程序使用的库联接,所以通常使用 g++ 来完成联接;
但在编译阶段,g++ 会自动调用 gcc,二者等价。
GCC常用参数选项:
4.2.2 Makefile
什么是Makefile?(Makefile是个文件)
一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,Makefile 文件定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 Makefile 文件就像一个 Shell 脚本一样,也可以执行操作系统的命令。
Makefile 带来的好处就是“自动化编译” ,一旦写好,只需要一个 make 命令,整个工程完全自动编译,极大的提高了软件开发的效率。make 是一个命令工具,是一个解释 Makefile 文件中指令的命令工具,一般来说,大多数的 IDE 都有这个命令,比如 Delphi 的 make,Visual C++ 的 nmake
,Linux 下 GNU 的 make
。
makefile文件命名和规则
文件命名:makefile或者Makefile(只能是这两种命名方式)
Makefile规则:一个Makefile文件中可以有一个或者多个规则
目标... : 依赖...
命令(shell命令)
...
目标:最终要生成的文件;
依赖:生成目标所需要的文件或者目标;
命令:通过执行命令对依赖操作生成目标(命令前必须Tab缩进)
Makefile中的其他规则一般都是为第一条规则服务的。
基本原理 --> Makefile1、Makefile2
1.命令在执行之前,需要先检查规则中的依赖是否存在:
- a.如果存在,执行命令;
- b.如果不存在,向下检查其它的规则,检查有没有一个规则是用来生成这个依赖的,如果找到了,则执行该规则中的命令
2.检测更新,在执行规则中的命令时,会比较目标和依赖文件的时间
- a.如果依赖的时间比目标的时间晚,需要重新生成目标
- b.如果依赖的时间比目标的时间早,目标不需要更新,对应规则中的命令不需要被执行
变量 --> Makefile3
模式匹配 --> Makefile4
函数 --> Makefile5
伪目标:
.PHONY:clean
clean:
rm $(objs) -f//删除所有.o文件
4.2.3 GDB调试
什么是GDB?
GDB 是由 GNU 软件系统社区提供的调试工具,同 GCC 配套组成了一套完整的开发环境,GDB 是 Linux 和许多类 Unix 系统中的标准开发环境。
一般来说,GDB 主要帮助你完成下面四个方面的功能:
- 启动程序,可以按照自定义的要求随心所欲的运行程序;
- 可让被调试的程序在所指定的调置的断点处停住(断点可以是条件表达式);
- 当程序被停住时,可以检查此时程序中所发生的事;
- 可以改变程序,将一个 BUG 产生的影响修正从而测试其他 BUG。
GDB说白了就是断点调试,排除开发过程中出现的bug。
通常,在为调试而编译时,我们会()关掉编译器的优化选项( -O
), 并打开调试选项( -g
)。
另外, -Wall
在尽量不影响程序行为的情况下选项打开所有 warning,也可以发现许多问题,避免一些不必要的 BUG。
gcc -g -Wall program.c -o program
-g
选项的作用是在可执行文件中加入源代码的信息,比如可执行文件中第几条机器指令对应源代码的第几行,但并不是把整个源文件嵌入到可执行文件中,所以在调试时必须保证 gdb 能找到源文件。
常用的GDB命令:
4.2.4 静态库
静态库的制作
什么是库?
库文件是计算机上的一类文件,可以简单的把库文件看成一种代码仓库,它提供给使用者一些可以直接拿来用的变量、函数或类。
库的特点:
库是特殊的一种程序,编写库的程序和编写一般的程序区别不大,只是库不能单独运行。
库的分类:库文件有两种,静态库和动态库(共享库);
- 静态库在程序的链接阶段被复制到了程序中;
- 动态库在链接阶段没有被复制到程序中,而是程序在运行时由系统动态加载到内存中供程序调用。
- (具体的原理和区别见1.7 动态库加载失败的原因)
库的好处:
1.代码保密 2.方便部署和分发。
命名规则:
(注意区分库文件的名字和库的名字)
libxxx.a //库文件的名字
lib :前缀(固定)
xxx :库的名字(自己起)
.a :后缀(固定)
静态库的制作:
1.获得目标代码.o
文件;
gcc -c a.c b.c
2.将.o
文件打包,使用ar
工具(archive)
ar rcs libxxx.a a.o b.o
示例:(静态库的制作)
在/calc
目录下,最开始有一个头文件,四个**.c文件**,和一个main.c文件
通过gcc -c
生成目标代码 xxx.o
;
再通过ar
指令制作静态库libcalc.a
。
静态库的使用
(视频课中是在/calc
目录下制作静态库,然后在/library
目录下又制作了一遍静态库,然后再使用静态库,所以直接在/library
目录下一次性完成制作+使用
静态库)
分发静态库的时候一定要把头文件和库文件一起分发出去,
(下面的示例的视频课链接:12:20开始)
示例:(静态库的制作和使用)
在/library
目录下,刚开始有3个文件夹,6个文件:
示例中会用到下面的几个参数:-I 路径
指定include包含文件的搜索目录;-l 路径
程序编译的时候,指定要使用的库的名称(即要使用哪个库);-L 路径
指定库的路径。
第1步:生成目标代码.o
提示找不到头文件,所以要指明去哪里搜索头文件:上级目录的/include文件夹下,即../include/
(注意是两个.
)
第2步:制作静态库libsuanshu.a
然后把静态库移动到上级目录下的/lib
文件夹下,即../lib/
第3步:使用静态库对main.c文件进行编译
编译的时候也是提示找不到头文件,所以要指明去哪里搜索头文件:当前目录的/include
文件夹下,即../include/
(注意是两个.
);
然后main函数中的函数未定义,而函数的定义在库文件中,所以要指定库文件的路径和要用哪个库;
最后生成可执行文件a.out
,运行即可。
注意:-l
后面加的是库的名称,而不是库文件的名称。
4.2.5 动态库
动态库的制作和使用
动态库的命名规则:
动态库的制作:
1.得到和位置无关的目标代码.o
文件;
(记得加-fpic
)
gcc -c -fpic a.c b.c
2.得到动态库
gcc -shared a.o b.o -o libcals.so
示例:(动态库的制作与使用)
在路径 /home/reus/牛客网-Linux高并发服务器开发/1.6动态库的制作和使用 下,有以下文件:
(和静态库的制作和使用一样,视频课中也是在/calc
目录下制作动态库,然后在/library
目录下又制作了一遍动态库,然后再使用动态库,所以直接在/library目录下一次性完成制作加使用动态库)
1.制作动态库,并放到/lib
目录下
2.使用动态库
和静态库的操作一样,但最后运行可执行文件的时候出错了(提示找不到动态库文件),具体见下一节。
./a.out: error while loading shared libraries: libcalc.so: cannot open shared object file: No such file or directory
动态库加载失败的原因
上一节中最后运行可执行文件a.out
的时候出错了,提示找不到动态库文件,所以需要学习下动态库的工作原理。
静态库和动态库的区别:
- 静态库:GCC 进行链接时,会把静态库中代码打包到可执行程序
a.out
中; - 动态库:GCC 进行链接时,动态库的代码不会被打包到可执行程序
a.out
中,而是在程序启动之后,将动态库动态地加载到内存中;
动态库的工作原理:
- 程序启动之后,动态库会被动态加载到内存中,通过
ldd
(list dynamic dependencies)命令检查动态库依赖关系; - 如何定位共享库文件呢?
当系统加载可执行代码时候,能够知道其所依赖的库的名字,但是还需要知道绝对路径,此时就需要系统的动态载入器来获取该绝对路径。
对于elf
格式的可执行程序,是由ld-linux.so
来完成的,它先后搜索elf
文件的DT_RPATH
段 ——> 环境变量LD_LIBRARY_PATH
——>/etc/ld.so.cache
文件列表 ——>/lib/
,/usr/lib
目录,找到库文件后将其载入内存。
在终端输入ldd a.out
,可以看出libcalc.so => not found
创建的动态库libcalc.so
未找到,具体的解决方法见下一节。
oot@VM-16-2-ubuntu:/home/reus/牛客网-Linux高并发服务器开发/1.6动态库的制作和使用/library# ldd a.out
linux-vdso.so.1 (0x00007fff6b7b4000)
libcalc.so => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fce25c3a000)
/lib64/ld-linux-x86-64.so.2 (0x00007fce25e3c000)
解决动态库加载失败的问题☆☆☆
环境变量:
env
环境变量是个键值对,一个键可以对应多个值,用冒号隔开。
那么如何配置动态库的绝对路径呢?
课里讲了两种方式:
- 把绝对路径放到环境变量
LD_LIBRARY_PATH
中; - 把路径放到
/etc/ld.so.cache
中。
(视频课中从07:40开始)
方式1:把绝对路径放到环境变量LD_LIBRARY_PATH
中;
刚开始讲了一种方式,是在终端上配置的,但把终端关闭后,就又找不到动态库了,这种配置是临时的。
具体实现如下:
1.先把动态库的绝对路径复制下来
pwd
/home/reus/牛客网-Linux高并发服务器开发/1.6动态库的制作和使用/library/lib
2.配置环境变量
export LD_LIBRARY_PATH=$LD_LIBRARY:/home/reus/牛客网-Linux高并发服务器开发/1.6动态库的制作和使用/library/lib
3.查看环境变量文章来源:https://www.toymoban.com/news/detail-609332.html
echo $LD_LIBRARY_PATH
:/home/reus/牛客网-Linux高并发服务器开发/1.6动态库的制作和使用/library/lib
4.退到上一层目录,通过ldd
命令检查动态库的依赖关系,不再是not found
文章来源地址https://www.toymoban.com/news/detail-609332.html
cd ..
ldd a.out
linux-vdso.so.1 (0x00007fff1933c000)
libcalc.so
到了这里,关于Linux高并发服务器开发---笔记1(环境搭建、系统编程、多进程)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!