最近打算通过TinyWebServer这个项目学习一下cpp。由于手头只有一台MacBook Air M2,项目的环境是Ubuntu.因此通过安装虚拟机来运行项目。但是由于M2时Arm架构,并且Ubuntu上没有项目对应的MySQ5.7版本,只能通过源码编译安装MySQL,过程比较崎岖。记录一下这个过程。
一、准备工作
-
安装ubuntu22.04虚拟机
-
注意,磁盘分配至少35GB
-
安装包vim,ssh,ping,net-tools
-
ssh登录,允许root登录
-
换源
-
-
编译安装mysql5.7
- boost问题(修改编译时boost路径)
- openssl版本太高(手动编译安装)
- 磁盘空间不够(重新安装虚拟机)
-
运行mysql
- 初始化mysql
- 创建systemd服务,修改MySQL密码
- 创建数据库
1. 虚拟机安装
安装虚拟机需要做的
- 安装包vim, ssh,ping,net-tools
- ssh登录,允许root登录
- 换源
sudo apt install iputils-ping
sudo apt-get update
sudo apt-get install openssh-server
sudo apt install vim
sudo apt install make
sudo apt install net-tools
换源
vim /etc/apt/sources.list
添加以下内容:
# 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-updates main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-updates main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-backports main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-backports main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-security main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-security main restricted universe multiverse
# 预发布软件源,不建议启用
# deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-proposed main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-proposed main restricted universe multiverse
2. 编译安装MySQL5.7
tar -xzf mysql-boost-5.7.44.tar.gz
mkdir build
cd build
# 安装一些依赖包
sudo apt update
sudo apt install cmake build-essential libncurses5-dev libaio-dev libssl-dev libedit-dev libreadline-dev zlib1g-dev libcurl4-openssl-dev libevent-dev libgoogle-perftools-dev libjemalloc-dev
配置编译参数
cmake .. \
-DCMAKE_INSTALL_PREFIX=/usr/local/mysql \
-DWITH_BOOST=boost \
-DWITH_SSL=yes \
-DWITH_ZLIB=bundled \
-DWITH_EDITLINE=bundled \
-DWITH_CURL=yes \
-DWITH_JEMALLOC=bundled \
-DWITH_SYSTEMD=1 \
-DCMAKE_C_FLAGS="-march=armv8-a" \
-DCMAKE_CXX_FLAGS="-march=armv8-a"
可能需要的操作
// cmake寻找依赖的包
sudo apt install pkg-config
export PKG_CONFIG_PATH=/usr/lib/x86_64-linux-gnu/pkgconfig
pkg-config --modversion openssl
// 安装openssl包
sudo apt update
sudo apt install libssl-dev
sudo apt install --reinstall libssl-dev openssl
报错1:找不到boost库
CMake Error at cmake/boost.cmake:88 (MESSAGE):
You can download it with -DDOWNLOAD_BOOST=1 -DWITH_BOOST=<directory>
This CMake script will look for boost in <directory>. If it is not there,
it will download and unpack it (in that directory) for you.
If you are inside a firewall, you may need to use an http proxy:
export http_proxy=http://example.com:80
Call Stack (most recent call first):
cmake/boost.cmake:174 (COULD_NOT_FIND_BOOST)
CMakeLists.txt:547 (INCLUDE)
解决:下载的是带有boost版本的源码,但是博客中的cmake参数找不到boost。改一下指定路径。
将boost的路径改为-DWITH_BOOST=$(pwd)/../boost/boost_1_59_0
.最终的编译参数如下:
cmake .. \
-DCMAKE_INSTALL_PREFIX=/usr/local/mysql \
-DWITH_BOOST=$(pwd)/../boost/boost_1_59_0
-DWITH_SSL=yes \
-DWITH_ZLIB=bundled \
-DWITH_EDITLINE=bundled \
-DWITH_CURL=yes \
-DWITH_JEMALLOC=bundled \
-DWITH_SYSTEMD=1 \
-DCMAKE_C_FLAGS="-march=armv8-a" \
-DCMAKE_CXX_FLAGS="-march=armv8-a"
报错2:找不到合适的 openssl包(安装步骤在最下面).
CMake Error at cmake/ssl.cmake:63 (MESSAGE):
Please install the appropriate openssl developer package.
Call Stack (most recent call first):
cmake/ssl.cmake:264 (FATAL_SSL_NOT_FOUND_ERROR)
CMakeLists.txt:579 (MYSQL_CHECK_SSL)
解决:手动安装openssl,并将cmake编译选项改成如下设置。
cmake .. \
-DCMAKE_INSTALL_PREFIX=/usr/local/mysql \
-DWITH_BOOST=$(pwd)/../boost/boost_1_59_0 \
-DWITH_SSL=/usr/local/openssl \
-DWITH_ZLIB=bundled \
-DWITH_EDITLINE=bundled \
-DWITH_CURL=yes \
-DWITH_JEMALLOC=bundled \
-DWITH_SYSTEMD=1 \
-DCMAKE_C_FLAGS="-march=armv8-a" \
-DCMAKE_CXX_FLAGS="-march=armv8-a"
3. 初始化MySQL
创建 MySQL 用户和组,创建一个专用的 MySQL 用户和组:
sudo groupadd mysql
sudo useradd -r -g mysql mysql
初始化数据目录,初始化 MySQL 数据目录:
cd /usr/local/mysql
sudo bin/mysqld --initialize --user=mysql # 注意,执行完这一步后会生成一个临时密码,要记录这个密码用于初始登录mysql。否则需要通过其他操作修改密码。
设置权限,设置 MySQL 目录的权限:
sudo chown -R mysql:mysql /usr/local/mysql
sudo chown -R mysql:mysql /usr/local/mysql/data
创建Mysql配置文件,在/etc/目录下创建my.cnf并保存,配置文件内容如下:
vim /etc/my.cnf
[mysqld]
# 基本配置
# skip-grant-tables # 免密登录
basedir = /usr/local/mysql
datadir = /usr/local/mysql/data
socket = /tmp/mysql.sock
port = 3306
pid-file = /usr/local/mysql/data/mysqld.pid
# 日志配置
log-error = /usr/local/mysql/data/error.log
slow-query-log = 1
slow-query-log-file = /usr/local/mysql/data/slow-query.log
# InnoDB 配置
innodb_data_home_dir = /usr/local/mysql/data
innodb_log_group_home_dir = /usr/local/mysql/data
innodb_buffer_pool_size = 8024M
innodb_log_file_size = 100M
innodb_flush_log_at_trx_commit = 1
innodb_file_per_table = 1
# 其他配置
max_connections = 151
max_allowed_packet = 16M
thread_stack = 192K
thread_cache_size = 8
key_buffer_size = 16M
#bind-address = 0.0.0.0
4. 创建systemd服务
在基于 systemd 的 Linux 系统(例如Ubuntu 16.04 及以上版本)中,可以通过创建一个专门的服务文件来配置和管理 MySQL 服务器的启动、停止等操作。
systemd:
- Linux 的一种初始化系统和服务管理器,用于启动系统、加载服务、以及管理服务的生命周期。
- 提供
systemctl
命令来控制服务(如启动、停止、重启等)。systemd 服务文件:
- 一个以
.service
结尾的配置文件,定义某个服务的行为(如启动命令、依赖项、日志路径等)。- 通常存放在
/etc/systemd/system/
目录中。为什么需要创建服务文件?
- 手动安装MySQL(如从源码编译或非标准包安装),没有自动创建相应的
mysqld
服务文件。为了通过systemctl
命令管理 MySQL,需要手动创建一个服务文件,告知系统如何启动 MySQL。
创建一个 systemd 服务文件来管理 MySQL 服务。创建文件 /etc/systemd/system/mysqld.service,内容如下
vim /etc/systemd/system/mysqld.service
[Unit]
Description=MySQL Server
After=network.target
[Service]
User=mysql
Group=mysql
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/bin/kill -SIGINT $MAINPID
ExecStart=/usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data --pid-file=/usr/local/mysql/data/mysqld.pid
[Install]
WantedBy=multi-user.target
启动 MySQL 服务,加载新的服务文件并启动 MySQL 服务:
# 重新加载 systemd 配置
sudo systemctl daemon-reload
# 启动 MySQL 服务:
sudo systemctl start mysqld
# 将 MySQL 设置为开机自启:
sudo systemctl enable mysqld
# 查看MySQL状态
sudo systemctl status mysqld
登录MySQl(密码是刚才初始化的生成的密码)并修改密码。
/usr/local/mysql/bin/mysql -u root -p
ALTER USER 'root'@'localhost' IDENTIFIED BY '123456';
5. 添加系统变量
目前只能通过 ./bin/mysql -uroot -p
登录,MySQL客户端不在全局环境变量中。想要直接通过MySQL命令访问,必须将MySQL的路径加入到环境变量中。
-
编辑环境变量文件:
sudo nano /etc/profile
-
在文件末尾添加:
export PATH=$PATH:/usr/local/mysql/bin
-
保存并应用更改:
source /etc/profile
-
验证是否生效:
mysql --version
6. 修改MySQL密码
- 修改登录权限
vim /etc/my.cnf
- 在[mysqld]部分添加。目的是免密登录。
skip-grant-tables
- 重启mysql服务
systemctl restart mysqld
- 登录mysql.这里可以直接输入空密码,回车。
mysql -uroot -p
- 修改密码
show databases;
use mysql;
show tables;
desc user; # 可以看到user表里面有一个authentication_string字段
update user set authentication_string=password("123456") where user ='root';
7. openssl编译安装
- 编译
wget https://www.openssl.org/source/openssl-1.1.1w.tar.gz
./config --prefix=/usr/local/openssl
./config -t
sudo make
sudo make install
- 链接OpenSSL所依赖的库文件
cd /usr/local/openssl/bin
ldd openssl
linux-vdso.so.1 (0x0000ffff905a9000)
libssl.so.1.1 => not found
libcrypto.so.1.1 => not found
libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6 (0x0000ffff902f0000)
/lib/ld-linux-aarch64.so.1 (0x0000ffff90570000)
注意not found
的两行,意思是libssl.so.1.1和libcrypto.so.1.1找不到所依赖的库文件,直接运行会抛openssl: error while loading shared libraries: libssl.so.1.1: cannot open shared object file: No such file or directory异常,解决方法为手动去连接库文件.
ln -s /usr/local/openssl/lib/libssl.so.1.1 /usr/lib64/libssl.so.1.1
ln -s /usr/local/openssl/lib/libcrypto.so.1.1 /usr/lib64/libcrypto.so.1.1
# 临时使用,也可以执行
export LD_LIBRARY_PATH=/usr/local/openssl/lib:$LD_LIBRARY_PATH
再次,ldd openssl
一下
linux-vdso.so.1 (0x0000ffff9a2a9000)
libssl.so.1.1 => /usr/local/openssl/lib/libssl.so.1.1 (0x0000ffff9a0f0000)
libcrypto.so.1.1 => /usr/local/openssl/lib/libcrypto.so.1.1 (0x0000ffff99e30000)
libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6 (0x0000ffff99c80000)
/lib/ld-linux-aarch64.so.1 (0x0000ffff9a270000)
- 修改配置文件
在/etc/profile最后一行添加
sudo vim /etc/profile
export OPENSSL=/usr/local/openssl/bin
export PATH=$OPENSSL:$PATH:$HOME/bin
source /etc/profile
验证是否生效
openssl version -a
二、运行代码
-
MySQL启动bug
× mysqld.service - MySQL Server Loaded: loaded (/etc/systemd/system/mysqld.service; enabled; vendor preset: enabled) Active: failed (Result: exit-code) since Mon 2024-12-02 10:43:41 UTC; 7h left Process: 759 ExecStart=/usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data --pid-file=/usr/local/mysql/data/mysqld.pid (code=exited, status=1/FAILURE) Main PID: 759 (code=exited, status=1/FAILURE) CPU: 732ms Dec 02 10:43:39 elephant systemd[1]: Started MySQL Server. Dec 02 10:43:41 elephant systemd[1]: mysqld.service: Main process exited, code=exited, status=1/FAILURE Dec 02 10:43:41 elephant systemd[1]: mysqld.service: Failed with result 'exit-code'.
解决:重新加载、启动服务
systemctl daemon-reload systemctl restart mysqld.service
-
创建数据库
通过终端进入mysql,创建TinyWebServer的数据库和表
# 进入数据库 mysql -uroot -p #接下来输入密码 // 建立tinywebserver库 create database tinywebserver; // 创建user表 USE tinywebserver; CREATE TABLE user( username char(50) NULL, passwd char(50) NULL )ENGINE=InnoDB; // 添加数据 INSERT INTO user(username, passwd) VALUES('elephant', '123456'); // 退出数据库 exit;
-
开放端口(其实不需要)
sudo apt install ufw sudo ufw allow 9006
-
编译代码
cd ./TinyWebServer chmod +x ./build.sh ./build.sh # 这里可能回报找不到mysql头文件类似的错误,安装一下依赖即可 sudo apt-get install mysql-server # 再次编译 ./build.sh
-
日志频繁报错mysql error
参考这个issue
在sql_connection_pool.cpp添加下面的调试代码.重新编译,再次运行,会输出数据库的连接错误.
// con = mysql_real_connect(con, url.c_str(), User.c_str(), PassWord.c_str(), DBName.c_str(), Port, NULL, 0); if (!mysql_real_connect(con, url.c_str(), User.c_str(), PassWord.c_str(), DBName.c_str(), Port, NULL, 0)) { cout << mysql_errno(con) << " " << mysql_error(con) << endl; exit(1); }
./server运行:
2002 Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)
这个错误
2002: Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)
表示 MySQL 客户端尝试通过指定的 Unix 套接字文件/var/run/mysqld/mysqld.sock
连接 MySQL 服务时失败.-
MySQL 服务未运行
通过
systemctl status mysqld
很容易验证正在运行。不是这个原因。 -
套接字文件不存在
ls -l /var/run/mysqld/mysqld.sock
没有输出。因此通过这个位置找sokcet文件是连接不上mysql的。
定位一下mysqld.sock的位置。locate,find都不行,直接在配置文件中找。
grep -i socket /etc/my.cnf /etc/mysql/my.cnf /etc/my.cnf:socket = /tmp/mysql.sock /etc/mysql/my.cnf:# Remember to edit /etc/mysql/debian.cnf when changing the socket location.
客户端尝试连接默认的 /var/run/mysqld/mysqld.sock,但服务器使用的是 /tmp/mysql.sock,从而产生无法找到套接字文件的错误。
**解决方案:**确保服务器和客户端的 socket 设置一致。
sudo mkdir -p /var/run/mysqld sudo ln -s /tmp/mysql.sock /var/run/mysqld/mysqld.sock sudo chown mysql:mysql /var/run/mysqld/mysqld.sock
创建软连接将 /tmp/mysql.sock 链接到 /var/run/mysqld/mysqld.sock
再次运行./server。成功。
-
三、参考链接
Mac在VMware Fusion安装Ubuntu22.04
c++ 经典服务器开源项目 Tinywebserver的使用与配置(百度智能云服务器安装ubuntu18.04可用公网ip访问)