<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>陈金保</title>
    <description>欢迎来到我的个人站~</description>
    <link>https://jinbao1chen.github.io/</link>
    <atom:link href="https://jinbao1chen.github.io/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Mon, 14 Feb 2022 14:03:46 +0000</pubDate>
    <lastBuildDate>Mon, 14 Feb 2022 14:03:46 +0000</lastBuildDate>
    <generator>Jekyll v3.9.0</generator>
    
      <item>
        <title>Win10安装MySQL5.7</title>
        <description>&lt;h2 id=&quot;note&quot;&gt;Note&lt;/h2&gt;
&lt;p&gt;记录一下Win10 64位 安装MySQL5.7教程。&lt;/p&gt;

&lt;h2 id=&quot;下载mysql&quot;&gt;下载MySQL&lt;/h2&gt;
&lt;p&gt;下载MySQL: https://downloads.mysql.com/archives/community/&lt;/p&gt;

&lt;p&gt;或者 链接：https://pan.baidu.com/s/1vMxm7oACw0L4tc8ZdF460w
提取码：ke2p&lt;/p&gt;

&lt;h2 id=&quot;安装教程&quot;&gt;安装教程&lt;/h2&gt;
&lt;p&gt;参考链接：https://blog.csdn.net/m0_37218227/article/details/109154009 ，按照链接一步步安装即可。&lt;/p&gt;

&lt;p&gt;如果链接失效，百度网盘备份，链接：https://pan.baidu.com/s/1kqvbZr54rMXb83Yq0y9zHA
提取码：i43e&lt;/p&gt;

&lt;p&gt;教程：Win10安装MySQL5.7，https://blog.csdn.net/baidu_36602427/article/details/88387630&lt;/p&gt;

&lt;h2 id=&quot;遇到问题解决方法&quot;&gt;遇到问题解决方法&lt;/h2&gt;
&lt;h3 id=&quot;由于找不到msvcr120dll无法继续执行代码重新安装程序可能会解决此问题&quot;&gt;“由于找不到MSVCR120.dll，无法继续执行代码。重新安装程序可能会解决此问题”&lt;/h3&gt;
&lt;p&gt;下载DirectXRepair 加强版(注：一定要是加强版，加强版才可以自动添加c++组件)，链接：https://pan.baidu.com/s/1K_sNBuwALHG82_4SPhqddw
提取码：kznh&lt;/p&gt;

&lt;p&gt;点击检测并修复，重启后即可。&lt;/p&gt;

&lt;h3 id=&quot;mysql数据库中设置root密码的命令及方法&quot;&gt;Mysql数据库中设置root密码的命令及方法&lt;/h3&gt;
&lt;p&gt;参考链接：https://www.cnblogs.com/ydwzhang/p/13944058.html&lt;/p&gt;

&lt;p&gt;C:\Program Files\MySQL\MySQL Server 5.1\bin&amp;gt;mysqladmin -u root -p password 123456&lt;/p&gt;

&lt;p&gt;Enter password:&lt;/p&gt;

&lt;p&gt;C:\Program Files\MySQL\MySQL Server 5.1\bin&amp;gt;mysql -u root -p123456&lt;/p&gt;

&lt;p&gt;　　如上所述使用mysqladmin第一次修改root的默认密码时，Enter password回车即可，然后使用mysql.exe命令输入root及其密码即可进入Mysql命令行。&lt;/p&gt;

&lt;h2 id=&quot;mysql命令&quot;&gt;MySQL命令&lt;/h2&gt;
&lt;p&gt;使用root进入：mysql -u root -p&lt;/p&gt;

&lt;p&gt;启动MySQL：net start mysql&lt;/p&gt;

&lt;p&gt;停止MySQL：net stop mysql&lt;/p&gt;

&lt;h2 id=&quot;该mysql无法配合qt工作还是重新安装了mysql80&quot;&gt;该mysql无法配合Qt工作，还是重新安装了mysql8.0&lt;/h2&gt;
&lt;p&gt;https://www.cnblogs.com/xiaokang01/p/12092160.html win10安装MySql教程&lt;/p&gt;
</description>
        <pubDate>Tue, 08 Feb 2022 00:00:00 +0000</pubDate>
        <link>https://jinbao1chen.github.io/2022/02/Win10%E5%AE%89%E8%A3%85MySQL5.7/</link>
        <guid isPermaLink="true">https://jinbao1chen.github.io/2022/02/Win10%E5%AE%89%E8%A3%85MySQL5.7/</guid>
        
        <category>工具，MySQL</category>
        
        
      </item>
    
      <item>
        <title>Qt工具QAQ</title>
        <description>&lt;h2 id=&quot;note&quot;&gt;Note&lt;/h2&gt;
&lt;p&gt;使用qt遇到的一些问题记录。&lt;/p&gt;

&lt;h2 id=&quot;qaq&quot;&gt;QAQ&lt;/h2&gt;
&lt;h3 id=&quot;1使用qt-5140自带的windeployqt打包程序提示unable-to-find-platform-plugin的解决方法&quot;&gt;1、使用Qt 5.14.0自带的windeployqt打包程序提示Unable to find Platform Plugin的解决方法&lt;/h3&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;C:\Qt\Qt5.14.0\5.14.0\mingw73_64&amp;gt;cd /d D:\QT_packtest

D:\QT_packtest&amp;gt;
D:\QT_packtest&amp;gt;
D:\QT_packtest&amp;gt;windeployqt TCPClient.exe
D:\QT_packtest\TCPClient.exe 64 bit, release executable
Direct dependencies: Qt5Core Qt5Gui Qt5Network Qt5Widgets
All dependencies   : Qt5Core Qt5Gui Qt5Network Qt5Widgets
To be deployed     : Qt5Core Qt5Gui Qt5Network Qt5Widgets
Unable to find the platform plugin.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;问题原因：Qt5.14.0版本太新，windeployqt不支持。
windeployqt does not work for MinGW QTBUG-80763 Will be fixed in 5.14.1&lt;/p&gt;

&lt;p&gt;解决方法：回滚至5.13.2，等待Qt官方更新5.14.1。
参考链接：https://blog.csdn.net/jtjljy/article/details/103829487&lt;/p&gt;

&lt;h3 id=&quot;2qt自带的windeployqt打包程序&quot;&gt;2、Qt自带的windeployqt打包程序&lt;/h3&gt;
&lt;p&gt;参考文档：https://www.jb51.net/article/229479.htm
如果链接不存在，参考文档链接：https://pan.baidu.com/s/1mka-1EBYlueO2ulYTlBG0Q
提取码：d7j4&lt;/p&gt;

&lt;p&gt;（1）通过release方式构建项目。构建套件中选择release选项后，重新run一遍项目；即可在原项目目录下找到构建项目的文件夹，进入release文件夹就可以看到exe文件，这个就是代码打包出来的文件，但是缺少QT对应的依赖，所以无法执行。将其单独放在一个文件夹下面，并复制此路径。&lt;/p&gt;

&lt;p&gt;（2）使用windeployqt工具添加依赖项。在任务管理器找到Qt命令行工具，直接搜索即可，注意要使用MinGW版本才能添加合适的依赖，也要注意bit位数，64位的项目不能用32位的MinGW来打包，这里项目和打包用的都是32位，因为32位的电脑多一些，所以兼容性会好一些（64位电脑能运行32位软件，32位软件不能运行64位电脑）
分别在此命令行工具下执行以下两条指令：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;进入待操作文件夹 cd+刚刚复制的路径

cd D:\Code\QT\test

使用windeployqt工具

windeployqt Demo.exe
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;构建完成的exe文件能在这个文件夹下面运行，但是脱离此文件夹依旧不能独立运行，所以后面使用Enigma Virtual Box打包。&lt;/p&gt;

&lt;p&gt;（3）使用Enigma Virtual Box打包。Enigma Virtual Box是软件虚拟化工具，它可以将多个文件封装到应用程序主文件，从而制作成为单执行文件的绿色软件。它支持所有类型的文件格式，虚拟化后的软件不释放任何临时文件到您的硬盘，文件模拟过程仅在内存运行&lt;/p&gt;

&lt;p&gt;Enigma Virtual Box下载路径： https://enigmaprotector.com/assets/files/enigmavb.exe 直接点击即可下载&lt;/p&gt;

&lt;p&gt;选择好输入输出路径，将需要打包的对应文件拖入打包区，点击process即可打包。这时候打包出来的Demo_boxed.exe文件就是可以独立运行和发布的exe文件了。&lt;/p&gt;

&lt;h3 id=&quot;3qt无法连接mysql&quot;&gt;3、Qt无法连接MySql&lt;/h3&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;QSqlDatabase: QMYSQL driver not loaded
QSqlDatabase: available drivers: QSQLITE QODBC QODBC3 QPSQL QPSQL7
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;原因：Qt里面的mysql驱动插件不对，需要重新编译对应mysql版本的插件。&lt;/p&gt;

&lt;p&gt;参考链接：Qt连接MySql驱动加载失败问题解决方法 https://blog.csdn.net/qq_38344751/article/details/105387341&lt;/p&gt;

&lt;p&gt;编译新驱动：&lt;/p&gt;

&lt;p&gt;（1）找到Qt安装目录源码 C:\Qt\Qt5.13.2\5.13.2\Src\qtbase\src\plugins\sqldrivers\mysql&lt;/p&gt;

&lt;p&gt;（2）将源码目录加载到Qt工程，并配置工程，出现锤子可编译&lt;/p&gt;

&lt;p&gt;（3）修改工程&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/*mysql.pro*/
TARGET = qsqlmysql

HEADERS += $$PWD/qsql_mysql_p.h
SOURCES += $$PWD/qsql_mysql.cpp $$PWD/main.cpp

#第一处修改，注释掉，因为后面会报错
#QMAKE_USE += mysql

OTHER_FILES += mysql.json

PLUGIN_CLASS_NAME = QMYSQLDriverPlugin
include(../qsqldriverbase.pri)
#include(C:\Qt\Qt5.13.2\5.13.2\Src\qtbase\src\plugins\sqldrivers/qsqldriverbase.pri)

#第二处修改，添加下载的mysql的库文件和头文件路径
#win32:LIBS += -LC:\Qt\windows\mysql-5.7.36-winx64\mysql-5.7.36-winx64\lib -llibmysql
#INCLUDEPATH += C:\Qt\windows\mysql-5.7.36-winx64\mysql-5.7.36-winx64\include
#DEPENDPATH += C:\Qt\windows\mysql-5.7.36-winx64\mysql-5.7.36-winx64\include
//以上为教程，Qt5.13连接MySQL过程记录https://blog.csdn.net/lougust/article/details/103337258，修改后弹出对话框，提示 qt中弹出“无法找到执行档，请指定一个”https://blog.csdn.net/weixin_47320074/article/details/119008180

//下面的修改是另一个教程里的，其实没太大差别，目的都是编译新插件的时候将MySql源码里的库包含进来。
INCLUDEPATH += C:\Qt\windows\mysql-5.7.36-winx64\mysql-5.7.36-winx64\include
LIBS += C:\Qt\windows\mysql-5.7.36-winx64\mysql-5.7.36-winx64\lib\libmysql.lib
DESTDIR = ../mysql/mysqlChen  //编译之后生成目标的目录
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;（4）点击锤子编译工程，如果qt中弹出“无法找到执行档，请指定一个”，我选择的是Qt安装目录里的编译器的qmake.exe, C:\Qt\Qt5.13.2\5.13.2\mingw73_64\bin\qmake.exe, 就执行完成编译，生成了新驱动文件。&lt;/p&gt;

&lt;p&gt;如果编译中出现 qtcreator启动显示 No winrtrunner.exe found. 不用理会。https://segmentfault.com/a/1190000020231619&lt;/p&gt;

&lt;p&gt;（5）将生成qsqlmysql.dll和qsqlmysqld.dll的新驱动文件放到 C:\Qt\Qt5.13.2\5.13.2\mingw73_64\bin，并且 mysql安装目录下的lib文件夹下的libmysql.dll，复制到qt的编译器的bin目录下，这样Qt就可以连接Mysql了。&lt;/p&gt;

&lt;p&gt;例如：win10安装Qt5.13.2 [1]、MySql-5.7.36(源码安装)[2] 以及腾讯云服务器(Ubuntu 源码安装Ubuntu18.04 源码编译安装mysql)MySql-5.37.6 [3]&lt;/p&gt;

&lt;h4 id=&quot;1win10安装qt带源码&quot;&gt;[1]Win10安装Qt带源码&lt;/h4&gt;
&lt;p&gt;（安装时选择源码，Qt5.13连接MySQL过程记录https://blog.csdn.net/lougust/article/details/103337258）&lt;/p&gt;

&lt;p&gt;安装Qt的时候要勾选Sources：Qt–&amp;gt;Qt5.13.2–&amp;gt;Sources&lt;/p&gt;

&lt;h4 id=&quot;2win10源码安装mysql&quot;&gt;[2]win10源码安装MySql&lt;/h4&gt;
&lt;p&gt;Win10 安装MySQL 5.7 详细教程https://blog.csdn.net/m0_37218227/article/details/109154009&lt;/p&gt;

&lt;h4 id=&quot;3腾讯云服务器ubuntu1804-源码编译安装mysqlmysql-5736&quot;&gt;[3]腾讯云服务器(Ubuntu18.04 源码编译安装mysql)MySql-5.7.36&lt;/h4&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;一、下载安装包
sudo su  //进入特权模式
//这样就可以不用经常切换特权模式
wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-boost-5.7.36.tar.gz
tar -zxvf mysql-5.7.36.tar.gz

二、安装依赖包
apt install cmake bison libncurses5-dev build-essential

三、编译安装
cd mysql-5.7.36/
cmake -DCMAKE_INSTALL_PREFIX=/usr/local/mysql -DMYSQL_DATADIR=/usr/local/mysql/data -DWITH_BOOST=boost
make &amp;amp;&amp;amp; make install

四、基本配置
添加用户组，和文件管理
groupadd mysql
useradd -g mysql mysql
mkdir /usr/local/mysql/data
chown -R mysql /usr/local/mysql
chgrp -R mysql /usr/local/mysql

五、初始化mysql
指定数据目录data位置 datadir
/usr/local/mysql/bin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data

这个会生成一个很随机的密码，要备份一下：我的是： dEFux53/NejH

六、编辑简单配置文件

注意端口号一般是3306，如果不行，就换别的，比如我的是3307

vim /etc/my.cnf
//添加下面的内容
[client]
socket = /tmp/mysql.sock

[mysqld]
port=3307
socket = /tmp/mysql.sock
basedir = /usr/local/mysql
datadir = /usr/local/mysql/data

七、启动mysql服务

一般启动或暂停模式：support-files/mysql.server start (stop)
下面把启动放到service下，可以快捷启动

cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld
chmod +x /etc/init.d/mysqld
update-rc.d mysqld defaults
service mysqld start

可能启动发生下面的错误，就要学会去看error.log

root@localhost mysql]# service mysql restart  
Starting MySQL...[ERROR] The server quit without updating PID file

一般在/usr/local/mysql/data 目录下面 我的是这个：DESKTOP-9I2JAHT.err
其实也可以在，my.cnf 指定error日志目录,如下面那个就很完备，据情况需要添加,有些目录需要先创建，比如logs，tmp，run

像我这个就是发生了端口冲突，所以改成了3307
————————————————

八、启动mysql
ln -s /usr/local/mysql/bin/mysql /usr/bin/mysql
mysql -uroot -p'dEFux53/NejH'

//重新修改密码 为123456
mysql&amp;gt; ALTER USER 'root'@'localhost' IDENTIFIED BY '123456';
exit 退出

修改一下my.cnf ,添加用户和密码
————————————————

九、设置远程连接

#所有主机都可以连接
mysql&amp;gt;GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123456' WITH GRANT OPTION;
mysql&amp;gt;flush privileges;
exit
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;参考链接：Ubuntu18.04 源码编译安装mysql https://blog.csdn.net/weixin_42973678/article/details/100107986&lt;/p&gt;

&lt;h4 id=&quot;4腾讯云开启3306端口&quot;&gt;[4]腾讯云开启3306端口&lt;/h4&gt;
&lt;p&gt;在腾讯云后台安全组中开放3306端口才能访问，进入 安全组控制台 ，找到 安全组 ，点击 修改规则 ，然后在入站规则里点击添加规则&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;类型:选择自定义
来源:0.0.0.0/0
协议端口:TPC:3306
策略:允许
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;参考链接：https://www.jianshu.com/p/7bc3ac757fed&lt;/p&gt;
</description>
        <pubDate>Tue, 01 Feb 2022 00:00:00 +0000</pubDate>
        <link>https://jinbao1chen.github.io/2022/02/QT%E4%BD%BF%E7%94%A8%E7%9B%B8%E5%85%B3%E7%9A%84QAQ/</link>
        <guid isPermaLink="true">https://jinbao1chen.github.io/2022/02/QT%E4%BD%BF%E7%94%A8%E7%9B%B8%E5%85%B3%E7%9A%84QAQ/</guid>
        
        <category>工具，Qt</category>
        
        
      </item>
    
      <item>
        <title>Libevent 服务器</title>
        <description>&lt;h2 id=&quot;note&quot;&gt;Note&lt;/h2&gt;
&lt;p&gt;利用Libevent搭建TCP服务器，可以接受TCP客户端的连接，并可进行数据读写&lt;/p&gt;

&lt;h2 id=&quot;服务端代码&quot;&gt;服务端代码&lt;/h2&gt;

&lt;p&gt;注意：编译的时候要加libevent库, gcc Libevent服务器.c -o Libevent服务器 -levent&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/**********************************************************************************************
常规创建服务器：
1、创建socket
2、bind 绑定socket
3、listen 监听
4、accept 连接
------------------------------------------------
Libevent创建服务器：
1、evconnlistener_new_bind()函数封装了创建、绑定、监听、连接等功能：
   **
    Allocate a new evconnlistener object to listen for incoming TCP connections
    on a given address. //创建监听对象，在指定的地址上监听接下来的TCP连接

    @param base The event base to associate the listener with.
     @param cb A callback to be invoked when a new connection arrives. If the
        callback is NULL, the listener will be treated as disabled until the
        callback is set.
     @param ptr A user-supplied pointer to give to the callback.
     @param flags Any number of LEV_OPT_* flags
     @param backlog Passed to the listen() call to determine the length of the
        acceptable connection backlog.  Set to -1 for a reasonable default.
     @param addr The address to listen for connections on.
     @param socklen The length of the address.
   **
   EVENT2_EXPORT_SYMBOL struct evconnlistener *evconnlistener_new_bind(struct event_base *base,
      evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
      const struct sockaddr *sa, int socklen);

2、unsigned flags参数：
 ** Flag: Indicates that we should not make incoming sockets nonblocking
 * before passing them to the callback. *
#define LEV_OPT_LEAVE_SOCKETS_BLOCKING	(1u&amp;lt;&amp;lt;0)  //阻塞，读不到卡住
 ** Flag: Indicates that freeing the listener should close the underlying
 * socket. *
#define LEV_OPT_CLOSE_ON_FREE		(1u&amp;lt;&amp;lt;1)  //关闭的时候释放监听对象
 ** Flag: Indicates that we should set the close-on-exec flag, if possible *
#define LEV_OPT_CLOSE_ON_EXEC		(1u&amp;lt;&amp;lt;2)
 ** Flag: Indicates that we should disable the timeout (if any) between when
 * this socket is closed and when we can listen again on the same port. *
#define LEV_OPT_REUSEABLE		(1u&amp;lt;&amp;lt;3)  //端口可以重复使用
 ** Flag: Indicates that the listener should be locked so it's safe to use
 * from multiple threadcs at once. *
#define LEV_OPT_THREADSAFE		(1u&amp;lt;&amp;lt;4)
 ** Flag: Indicates that the listener should be created in disabled
 * state. Use evconnlistener_enable() to enable it later. *
#define LEV_OPT_DISABLED		(1u&amp;lt;&amp;lt;5)
 ** Flag: Indicates that the listener should defer accept() until data is
 * available, if possible.  Ignored on platforms that do not support this.
 *
 * This option can help performance for protocols where the client transmits
 * immediately after connecting.  Do not use this option if your protocol
 * _doesn't_ start out with the client transmitting data, since in that case
 * this option will sometimes cause the kernel to never tell you about the
 * connection.
 *
 * This option is only supported by evconnlistener_new_bind(): it can't
 * work with evconnlistener_new_fd(), since the listener needs to be told
 * to use the option before it is actually bound.
 *
#define LEV_OPT_DEFERRED_ACCEPT		(1u&amp;lt;&amp;lt;6)
 ** Flag: Indicates that we ask to allow multiple servers (processes or
 * threads) to bind to the same port if they each set the option.
 *
 * SO_REUSEPORT is what most people would expect SO_REUSEADDR to be, however
 * SO_REUSEPORT does not imply SO_REUSEADDR.
 *
 * This is only available on Linux and kernel 3.9+
 *
#define LEV_OPT_REUSEABLE_PORT		(1u&amp;lt;&amp;lt;7)
 ** Flag: Indicates that the listener wants to work only in IPv6 socket.
 *
 * According to RFC3493 and most Linux distributions, default value is to
 * work in IPv4-mapped mode. If there is a requirement to bind same port
 * on same ip addresses but different handlers for both IPv4 and IPv6,
 * it is required to set IPV6_V6ONLY socket option to be sure that the
 * code works as expected without affected by bindv6only sysctl setting in
 * system.
 *
 * This socket option also supported by Windows.
 *
#define LEV_OPT_BIND_IPV6ONLY		(1u&amp;lt;&amp;lt;8)

3、回调函数原型：
 **
   A callback that we invoke when a listener has a new connection.

   @param listener The evconnlistener
   @param fd The new file descriptor
   @param addr The source address of the connection
   @param socklen The length of addr
   @param user_arg the pointer passed to evconnlistener_new()
 *
typedef void (*evconnlistener_cb)(struct evconnlistener *, evutil_socket_t, struct sockaddr *, int socklen, void *);

4、bufferevent_socket_new函数
  **
  Create a new socket bufferevent over an existing socket.

  @param base the event base to associate with the new bufferevent.
  @param fd the file descriptor from which data is read and written to.
	    This file descriptor is not allowed to be a pipe(2).
	    It is safe to set the fd to -1, so long as you later
	    set it with bufferevent_setfd or bufferevent_socket_connect().
  @param options Zero or more BEV_OPT_* flags
  @return a pointer to a newly allocated bufferevent struct, or NULL if an
	  error occurred
  @see bufferevent_free()
  *
EVENT2_EXPORT_SYMBOL
struct bufferevent *bufferevent_socket_new(struct event_base *base, evutil_socket_t fd, int options);

//属性设置
  ** Options that can be specified when creating a bufferevent *
  enum bufferevent_options {
	 ** If set, we close the underlying file
	 * descriptor/bufferevent/whatever when this bufferevent is freed. *
	BEV_OPT_CLOSE_ON_FREE = (1&amp;lt;&amp;lt;0),

	 ** If set, and threading is enabled, operations on this bufferevent
	 * are protected by a lock *
	BEV_OPT_THREADSAFE = (1&amp;lt;&amp;lt;1),

	 ** If set, callbacks are run deferred in the event loop. *
	BEV_OPT_DEFER_CALLBACKS = (1&amp;lt;&amp;lt;2),

	** If set, callbacks are executed without locks being held on the
	* bufferevent.  This option currently requires that
	* BEV_OPT_DEFER_CALLBACKS also be set; a future version of Libevent
	* might remove the requirement.*
	BEV_OPT_UNLOCK_CALLBACKS = (1&amp;lt;&amp;lt;3)
  };

5、给bufferevent设置回调函数 bufferevent_setcb
  **
  Changes the callbacks for a bufferevent.

  @param bufev the bufferevent object for which to change callbacks
  @param readcb callback to invoke when there is data to be read, or NULL if
	 no callback is desired
  @param writecb callback to invoke when the file descriptor is ready for
	 writing, or NULL if no callback is desired
  @param eventcb callback to invoke when there is an event on the file
	 descriptor
  @param cbarg an argument that will be supplied to each of the callbacks
	 (readcb, writecb, and errorcb)
  @see bufferevent_new()
  *
EVENT2_EXPORT_SYMBOL
void bufferevent_setcb(struct bufferevent *bufev,
    bufferevent_data_cb readcb, bufferevent_data_cb writecb,
    bufferevent_event_cb eventcb, void *cbarg);

6、使能bufferevent对象bufferevent_enable函数
  **
  Enable a bufferevent.

  @param bufev the bufferevent to be enabled
  @param event any combination of EV_READ | EV_WRITE.
  @return 0 if successful, or -1 if an error occurred
  @see bufferevent_disable()
  *
  EVENT2_EXPORT_SYMBOL int bufferevent_enable(struct bufferevent *bufev, short event);

7、回调函数read_cb原型：
  **
   A read or write callback for a bufferevent.

   The read callback is triggered when new data arrives in the input
   buffer and the amount of readable data exceed the low watermark
   which is 0 by default.

   The write callback is triggered if the write buffer has been
   exhausted or fell below its low watermark.

   @param bev the bufferevent that triggered the callback
   @param ctx the user-specified context for this bufferevent
  *
typedef void (*bufferevent_data_cb)(struct bufferevent *bev, void *ctx);

8、bufferevent_read函数原型：从bufferevent对象中读取数据
  **
  Read data from a bufferevent buffer.

  The bufferevent_read() function is used to read data from the input buffer.

  @param bufev the bufferevent to be read from
  @param data pointer to a buffer that will store the data
  @param size the size of the data buffer, in bytes
  @return the amount of data read, in bytes.
  *
  EVENT2_EXPORT_SYMBOL
  size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size);

9、回调函数bufferevent_event_cb原型：如果不是读\写事件之外的事件
  **
   An event/error callback for a bufferevent.

   The event callback is triggered if either an EOF condition or another
   unrecoverable error was encountered.

   For bufferevents with deferred callbacks, this is a bitwise OR of all errors
   that have happened on the bufferevent since the last callback invocation.

   @param bev the bufferevent for which the error condition was reached
   @param what a conjunction of flags: BEV_EVENT_READING or BEV_EVENT_WRITING
	  to indicate if the error was encountered on the read or write path,
	  and one of the following flags: BEV_EVENT_EOF, BEV_EVENT_ERROR,
	  BEV_EVENT_TIMEOUT, BEV_EVENT_CONNECTED.

   @param ctx the user-specified context for this bufferevent
  *
typedef void (*bufferevent_event_cb)(struct bufferevent *bev, short what, void *ctx);

************************************************************************************************/

#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;event.h&amp;gt;
#include &amp;lt;sys/socket.h&amp;gt;
#include &amp;lt;netinet/in.h&amp;gt;
#include &amp;lt;arpa/inet.h&amp;gt;
#include &amp;lt;event2/listener.h&amp;gt;
#include &amp;lt;string.h&amp;gt;

//bufferevent对象读\写之外的事件，
void event_cb(struct bufferevent *bev, short what, void *ctx)
{
    printf(&quot;异常发生！%x \n&quot;, what);
    if(what &amp;amp; BEV_EVENT_EOF)  //以 ctrl+C 为例，当客户端断开，便会触发该回调类型
    {
        //printf(&quot;客户端 %d 下线\n&quot;, *(int*)ctx);  //容易传局部参数,不建议传

        printf(&quot;客户端下线\n&quot;);
        //释放bufferevent对象
        bufferevent_free(bev);
    }
    else
    {
        printf(&quot;未知错误！\n&quot;);
    }
}

//回调函数read_cb实现，读取数据。参数：bufferevent对象、回调函数入参（可将fd传入，知道当前的连接fd是谁）
void read_cb(struct bufferevent *bev, void *ctx)
{
    //int fd = *(int*)ctx;  //容易传局部参数，不建议
    //读取数据
    char buf[128] = {0};
    size_t ret =  bufferevent_read(bev, buf, sizeof(buf));
    if(0 &amp;gt; ret)
    {
        printf(&quot;bufferevent_read error\n&quot;);
    }
    else
    {
        //printf(&quot;read from %d %s \n&quot;, fd, buf);

        printf(&quot;read %s \n&quot;, buf);
    }
}

void listener_cb(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *addr, int socklen, void *arg)
{
    printf(&quot;服务器接收 %d 的连接\n&quot;, fd);

    struct event_base *base = arg;
    //针对已经存在的socket创建bufferevent对象。实际上是将TCP连接socket与bufferevent绑定起来建立连接
    //参数：事件集合（从主函数传递过来）、fd(代表TCP连接，一个客户端一个连接，fd不同)、属性设置BEV_OPT_CLOSE_ON_FREE（如果释放bufferevent对象则关闭连接）
    struct bufferevent *bev =  bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
    if(NULL == bev)
    {
	printf(&quot;bufferevent_socket_new error!\n&quot;);
	exit(1);
    }

    //给bufferevent设置回调函数
    //参数：bufferevent对象、读事件回调函数、写事件回调函数、其他事件回调函数、回调函数入参（无参数用NULL，将fd地址传给回调函数）
    bufferevent_setcb(bev, read_cb, NULL, event_cb, &amp;amp;fd);

    //使能bufferevent对象,使bufferevent对象生效,读功能。
    bufferevent_enable(bev, EV_READ);


}

int main()
{
    //创建一个事件集合
    struct event_base *base = event_base_new();
    if(NULL == base)
    {
        printf(&quot;event_base_new error! \n&quot;);
        exit(1);
    }

    struct sockaddr_in server_addr;
    memset(&amp;amp;server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = 8000;
    server_addr.sin_addr.s_addr = inet_addr(&quot;127.0.0.1&quot;);     

    //创建socket、绑定、监听、接受连接；创建监听对象，在指定的地址上监听接下来的TCP连接
    //参数：监听集合、回调函数(连接到来会触发调用)、回调参数、属性设置(释放监听对象关闭socket|端口重复使用、接收队列长度、绑定接收地址、地址长度
    struct evconnlistener *listener =  evconnlistener_new_bind(base, listener_cb, base, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 10, (struct sockaddr *)&amp;amp;server_addr, sizeof(server_addr));
    if(NULL == listener)
    {
	printf(&quot;evconnlistener_new_bind error! \n&quot;);
	exit(1);
    }

    //监听集合中的事件
    event_base_dispatch(base);

    //释放两个对象,base对象和监听对象
    evconnlistener_free(listener);
    event_base_free(base);



    return 0;
 }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;测试客户端&quot;&gt;测试客户端&lt;/h2&gt;

&lt;dl&gt;
  &lt;dt&gt;NOTE: 运行客户端显示“connect error!&lt;/dt&gt;
  &lt;dd&gt;Connection refused
” 待解决。&lt;/dd&gt;
&lt;/dl&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;unistd.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;netinet/in.h&amp;gt;
#include &amp;lt;arpa/inet.h&amp;gt;
#include &amp;lt;sys/socket.h&amp;gt;
#include &amp;lt;sys/types.h&amp;gt;
#include &amp;lt;errno.h&amp;gt;

#define IP    &quot;127.0.0.1&quot;
#define PORT  8000

int main()
{
    int ret = -1;
    char buf[128] = {0};

    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if(-1 == fd)
    {
        printf(&quot;create socket error! \n&quot;);
        exit(1);
    }

    struct sockaddr_in server_addr;
    memset(&amp;amp;server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;            //设置tcp协议族
    server_addr.sin_port   = htons(PORT);        //设置端口号
    server_addr.sin_addr.s_addr = inet_addr(IP); //设置连接服务器ip地址

    ret = connect(fd, (struct sockaddr *)&amp;amp;server_addr, sizeof(server_addr));
    if(-1 == ret)
    {
        perror(&quot;connect\n&quot;);
       // printf(&quot;connect error! ret = %d \n&quot;,ret);
        close(fd);
        exit(1);
    }

    while(1)
    {
        printf(&quot;Input: \n&quot;);
        scanf(&quot;%s&quot;, buf);

        ret = send(fd, buf, sizeof(buf), 0);
        if(-1 == ret)
        {
	    printf(&quot;send error! \n&quot;);
            close(fd);
            exit(1);
        }
    }

    close(fd);

    return 0;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Mon, 03 Jan 2022 00:00:00 +0000</pubDate>
        <link>https://jinbao1chen.github.io/2022/01/Libevent%E6%9C%8D%E5%8A%A1%E5%99%A8/</link>
        <guid isPermaLink="true">https://jinbao1chen.github.io/2022/01/Libevent%E6%9C%8D%E5%8A%A1%E5%99%A8/</guid>
        
        <category>C，网络通信</category>
        
        
      </item>
    
      <item>
        <title>Qt工具</title>
        <description>&lt;h2 id=&quot;qt简介&quot;&gt;Qt简介&lt;/h2&gt;
&lt;p&gt;跨平台C++图形用户界面应用程序开发框架&lt;/p&gt;

&lt;p&gt;特点：&lt;/p&gt;

&lt;p&gt;1、面向对象&lt;/p&gt;

&lt;p&gt;2、控件间相互通信&lt;/p&gt;

&lt;p&gt;3、友好的联机帮助：库使用说明&lt;/p&gt;

&lt;p&gt;4、用户自定义&lt;/p&gt;

&lt;p&gt;5、方便性&lt;/p&gt;

&lt;p&gt;等等&lt;/p&gt;

&lt;h2 id=&quot;qt下载&quot;&gt;Qt下载&lt;/h2&gt;
&lt;p&gt;https://download.qt.io/archive/qt/&lt;/p&gt;

&lt;h2 id=&quot;qt安装&quot;&gt;Qt安装&lt;/h2&gt;
&lt;p&gt;https://blog.csdn.net/qq_42041303/article/details/122517594&lt;/p&gt;

&lt;h2 id=&quot;qt教程&quot;&gt;Qt教程&lt;/h2&gt;
&lt;h3 id=&quot;信号与槽&quot;&gt;信号与槽&lt;/h3&gt;
&lt;p&gt;//导入Qt工程学习四种创建信号与槽的方法（Qt创建Widget UI之后，点击或回车等UI界面时的反馈，如何将信号与槽函数关联）&lt;/p&gt;

&lt;p&gt;链接：https://pan.baidu.com/s/1Jy3bng9hIonZ94GwT6u3yA
提取码：fbwf&lt;/p&gt;

&lt;h3 id=&quot;四则运算计算器实现&quot;&gt;四则运算计算器实现&lt;/h3&gt;
&lt;p&gt;学习知识点：Qt设置窗口大小、字体、按钮放图片、改变按钮背景色、容器、网格布局&lt;/p&gt;

&lt;p&gt;1、添加Push Button，形成计算器样式，修改每个对象的名字便于后续操作&lt;/p&gt;

&lt;p&gt;2、添加Line Edit作为计算器的显示&lt;/p&gt;

&lt;p&gt;3、设置点击每个按钮后，有对应的显示。点击每个按钮，右键转到槽，选择信号clicked()，写槽函数&lt;/p&gt;

&lt;p&gt;链接：https://pan.baidu.com/s/166e4w5DTsGOrrNF6X-vz1w
提取码：js7n&lt;/p&gt;

&lt;h3 id=&quot;定时器&quot;&gt;定时器&lt;/h3&gt;
&lt;p&gt;Qt里定时器有两种：（1）QObject:startTimer killTimer (2)QTimer&lt;/p&gt;

&lt;p&gt;例子：定时显示图片，类似图片播放器。需要用到标签，把图片放到标签里&lt;/p&gt;

&lt;h4 id=&quot;1qobject-实现定时器&quot;&gt;(1)QObject 实现定时器&lt;/h4&gt;

&lt;p&gt;如果图片不能显示全，进入widget_ui –&amp;gt; QLable –&amp;gt; 勾选适配 scaledContents&lt;/p&gt;

&lt;p&gt;主要几个函数：startTimer()、killTimer()、setPixmap()&lt;/p&gt;

&lt;p&gt;链接：https://pan.baidu.com/s/11nsCbd1KqB8Rj78NSE9PXw
提取码：mlc6&lt;/p&gt;

&lt;h4 id=&quot;2qtimer-实现定时器&quot;&gt;(2)QTimer 实现定时器&lt;/h4&gt;
&lt;p&gt;链接：https://pan.baidu.com/s/1xPs2imznCIm5Ag8mOkjbCw
提取码：zcu9&lt;/p&gt;

&lt;p&gt;要点：创建QTimer定时器对象指针并初始化 timer = new QTimer;
//显示图片，另一种方法，使用QImage对象&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    QImage img;
    img.load(&quot;D:\\Qt_project\\QTimer\\1.jpg&quot;);
    ui-&amp;gt;label-&amp;gt;setPixmap(QPixmap::fromImage(img));
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;//定时器时间到，发出timeout信号&lt;/p&gt;

&lt;p&gt;//谁发出信号 发出什么信号 谁来处理 怎么处理（槽函数）&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;connect(timer, &amp;amp;QTimer::timeout, this, &amp;amp;Widget::timeoutSlot);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;//实现槽函数处理&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;void Widget::timeoutSlot()
{
    QString path(&quot;D:\\Qt_project\\QTimer\\&quot;);
    path += QString::number(pictureId);
    path += &quot;.jpg&quot;;

    //创建图片对象
    QImage img;
    img.load(path);
    //显示图片
    ui-&amp;gt;label-&amp;gt;setPixmap(QPixmap::fromImage(img));

    pictureId++;
    if(6 == pictureId)
    {
        pictureId = 1;
    }

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;文件操作&quot;&gt;文件操作&lt;/h3&gt;
&lt;p&gt;链接：https://pan.baidu.com/s/1jHeQBzKNcsiEXMZfN-PQQg
提取码：5puv&lt;/p&gt;

&lt;p&gt;预览快捷键：ALT + Shift + R&lt;/p&gt;

&lt;p&gt;菜单栏：menuBar; 菜单：menu_F/E/B; 动作：action_N/O/S&lt;/p&gt;

&lt;p&gt;主要步骤：创建ui对象 –&amp;gt; connect连接函数（谁发出信号、发出什么信号、谁来处理、怎么处理（槽函数）） –&amp;gt; 槽函数声明（private slots:
    void newActionSlot();）private slots –&amp;gt; 槽函数具体实现&lt;/p&gt;

&lt;p&gt;文件读写：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;//打开 槽函数具体实现
void MainWindow::openActionSlot()
{
    //跳出对话框(记住，使用了类 QFileDialog)
    //QFileDialog::getOpenFileName(this, tr(&quot;Open File&quot;),
    //                                                  &quot;/home&quot;,
    //                                                  tr(&quot;Images (*.png *.xpm *.jpg)&quot;));

    QString fileName = QFileDialog::getOpenFileName(this, &quot;选择一个文件&quot;,
                           QCoreApplication::applicationFilePath(), //获取当前路径
                                 &quot;*.cpp&quot;);                          //只显示.cpp类型文件
    if(fileName.isEmpty())
    {
        //如果为空，弹出一个提示的对话框
        QMessageBox::warning(this, &quot;警告&quot;, &quot;请选择一个文件&quot;);
    }
    else
    {
        //如果不为空，将该文件的名字打印出来。Qt如何打印？类似与c++的cout 使用QDebug类
        //qDebug() &amp;lt;&amp;lt; fileName;

        //打开该文件并显示内容
        QFile file(fileName);             //创建文件对象
        file.open(QIODevice::ReadOnly);    //如果文件比较少，可以用该方式。如果文件内容比较多，涉及效率问题，需采用其他方式
        QByteArray ba = file.readAll();         //返回值类型QByteArray
        //显示内容
        ui-&amp;gt;textEdit-&amp;gt;setText(QString(ba));            //将内容转为QString类型，并作为入参
        file.close();
    }
}

//保存 槽函数具体实现
void MainWindow::saveActionSlot()
{
    //跳转对话框，找到路径
    QString fileName = QFileDialog::getSaveFileName(this, &quot;请选择一个文件&quot;, QCoreApplication::applicationFilePath());
    if(fileName.isEmpty())
    {
        QMessageBox::warning(this, &quot;警告&quot;, &quot;请选择一个文件&quot;);
    }
    else
    {
        QFile file(fileName);
        file.open(QIODevice::WriteOnly);    //写内容
        //ui-&amp;gt;textEdit-&amp;gt;toPlainText();        //显示内容
        QByteArray ba;                      //创建QByteArray对象
        ba.append(ui-&amp;gt;textEdit-&amp;gt;toPlainText());                        //将显示的内容追加到QByteArray对象后面
        file.write(ba);
        file.close();
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;事件实现文件保存&quot;&gt;事件实现文件保存&lt;/h3&gt;
&lt;p&gt;链接：https://pan.baidu.com/s/1avpJypq0g4pALQC6X_fjCw
提取码：u3c3&lt;/p&gt;

&lt;p&gt;消息基础：
application能够知道哪个窗口在哪个位置，能够知道应该由哪个窗口来接收消息，这个窗口会调用自己的消息处理函数。&lt;/p&gt;

&lt;p&gt;窗口的 event（）函数处理所有经过窗口的消息。&lt;/p&gt;

&lt;p&gt;消息处理函数是虚函数，使用要进行重载。&lt;/p&gt;

&lt;p&gt;常见的QT事件类型如下：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;键盘事件：按键按下和松开
鼠标事件：鼠标移动，鼠标按键的按下和松开
拖放事件：用鼠标进行拖放
滚轮事件：鼠标滚轮滚动
绘屏事件：重绘屏幕的某些部分
定时事件：定时器到时
焦点事件：键盘焦点移动
进入和离开事件：鼠标移入widget之内，或是移出
移动事件：widget的位置改变
大小改变事件：widget的大小改变
显示和隐藏事件：widget显示和隐藏
窗口事件：窗口是否为当前窗口
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;QT将系统产生的消息转化为QT事件，QT事件被封装为对象，所有的QT事件均继承抽象类QEvent,用于描述程序内部或外部发生的动作，任意的QObject对象都具备处理QT事件的能力。&lt;/p&gt;

&lt;h4 id=&quot;键盘事件&quot;&gt;键盘事件&lt;/h4&gt;
&lt;p&gt;检测键盘按键的宏定义，“帮助–&amp;gt;搜索KeyEvnet” 可以找到键盘响应按键定义。&lt;/p&gt;

&lt;p&gt;普通按键：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;key : int

This property holds the code of the key that was pressed or released.
See Qt.Key （点击进去可以查到几乎所有按键宏定义）for the list of keyboard codes. These codes are independent of the underlying window system. Note that this function does not distinguish between capital and non-capital letters; use the text property for this purpose.
A value of either 0 or Qt.Key_Unknown means that the event is not the result of a known key; for example, it may be the result of a compose sequence, a keyboard macro, or due to key event compression.


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;常用按键：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;modifiers : int

This property holds the keyboard modifier flags that existed immediately before the event occurred.
It contains a bitwise combination of:
Qt.NoModifier - No modifier key is pressed.
Qt.ShiftModifier - A Shift key on the keyboard is pressed.
Qt.ControlModifier - A Ctrl key on the keyboard is pressed.
Qt.AltModifier - An Alt key on the keyboard is pressed.
Qt.MetaModifier - A Meta key on the keyboard is pressed.
Qt.KeypadModifier - A keypad button is pressed.
Qt.GroupSwitchModifier - X11 only. A Mode_switch key on the keyboard is pressed.
For example, to react to a Shift key + Enter key combination:

  Item {
      focus: true
      Keys.onPressed: {
          if ((event.key == Qt.Key_Enter) &amp;amp;&amp;amp; (event.modifiers &amp;amp; Qt.ShiftModifier))
              doSomething();
      }
  }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;键盘事件示例：
1、包含头文件 #include &amp;lt;QKeyEvent&amp;gt;
2、声明虚函数 void keyPressEvent(QKeyEvent *k);
3、重载虚函数
//重写虚函数
void MainWindow::keyPressEvent(QKeyEvent *k)
{
    //检测 CTRL + S 按键信号
    if(k-&amp;gt;modifiers() == Qt::ControlModifier &amp;amp;&amp;amp; k-&amp;gt;key() == Qt::Key_S)
    {
        saveActionSlot();
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;鼠标事件&quot;&gt;鼠标事件&lt;/h4&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;帮助--&amp;gt; 搜索&quot;MouseEvent&quot; 可以查看一些鼠标动作信号宏定义，如下：
button : enumeration

This property holds the button that caused the event. It can be one of:
Qt.LeftButton
Qt.RightButton
Qt.MiddleButton

键盘事件示例：
1、包含头文件 #include &amp;lt;QMouseEvent&amp;gt;
2、声明虚函数 void mousePressEvent(QMouseEvent *m);
3、重载事件函数
//重写虚函数，鼠标事件
void MainWindow::mousePressEvent(QMouseEvent *m)
{
    QPoint pt = m-&amp;gt;pos();   //QPoint类，获取鼠标位置
    qDebug() &amp;lt;&amp;lt; pt;         //打印鼠标位置

    //检测鼠标动作
    if(m-&amp;gt;button() == Qt::LeftButton)
    {
        qDebug() &amp;lt;&amp;lt; &quot;左键被按下&quot;;
    }
    else if(m-&amp;gt;button() == Qt::RightButton)
    {
        qDebug() &amp;lt;&amp;lt; &quot;右键被按下&quot;;
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;tcp客户端&quot;&gt;TCP客户端&lt;/h3&gt;
&lt;h4 id=&quot;linux中tcp连接&quot;&gt;Linux中TCP连接&lt;/h4&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;服务器                               客户端
socket(创建)              |          socket
bind(绑定)                |          
listen(监听)              |         
accept(接受客户端连接)     |          connect
send/recv(发送/接收数据)   |          send/recv
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h4 id=&quot;qt网络连接&quot;&gt;Qt网络连接&lt;/h4&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1、需要在工程里加上 “network”
D:\Qt_project\TCPClient\TCPClient.pro ：&quot;QT       += core gui network&quot;
2、创建socket对象
#include &amp;lt;QTcpSocket&amp;gt;     //包含头文件
QTcpSocket *socket;       //声明对象指针
socket = new QTcpSocket;  //创建socket对象
3、获取服务器ip地址和端口号，并连接服务器（使用socket成员函数connectToHost）
void QNetworkAccessManager::connectToHost(const QString &amp;amp;hostName, quint16 port = 80)
Initiates a connection to the host given by hostName at port port. This function is useful to complete the TCP handshake to a host before the HTTP request is made, resulting in a lower network latency.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h4 id=&quot;客户端&quot;&gt;客户端&lt;/h4&gt;
&lt;p&gt;链接：https://pan.baidu.com/s/1UmRmrQ-jVIl8aFi1zHAgxA
提取码：1bg8&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;//连接槽函数实现：点击&quot;连接&quot;时，先获取ip地址和端口号
void Widget::on_connectButton_clicked()
{
    //获取ip地址,获取QString类型，后面需转换为QHostAddress类型类型（如何转换？ QHostAddress(const QString &amp;amp;address)）
    QString IP = ui-&amp;gt;ipLineEdit-&amp;gt;text();
    //获取端口号
    QString Port = ui-&amp;gt;portLineEdit-&amp;gt;text();

    //连接服务器.connectToHost函数参数：主机名（QHostAddress类型）、端口号（quint16类型）
    socket-&amp;gt;connectToHost(QHostAddress(IP), Port.toShort());

    //连接服务器成功，socket对象会发出信号
    connect(socket, &amp;amp;QTcpSocket::connected, [this]()
    {
       QMessageBox::information(this, &quot;连接提示&quot;, &quot;连接服务器成功&quot;);
    });

    //连接断开，socket也会发出信号
    connect(socket, &amp;amp;QTcpSocket::disconnected, [this]()
    {
        QMessageBox::warning(this, &quot;连接提示&quot;, &quot;连接异常 断开服务器&quot;);
    });
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;tcp服务器&quot;&gt;TCP服务器&lt;/h3&gt;
&lt;p&gt;链接：https://pan.baidu.com/s/17IM1Qn5B5_YU3HUinAkqEw
提取码：2prm&lt;/p&gt;
&lt;h4 id=&quot;1头文件&quot;&gt;1、头文件&lt;/h4&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#include &amp;lt;QTcpSocket&amp;gt;     //tcp服务器头文件
#include &amp;lt;QHostAddress&amp;gt;
#include &amp;lt;QMessageBox&amp;gt;

QTcpSocket *socket;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h4 id=&quot;2创建tcpserver对象&quot;&gt;2、创建tcpserver对象&lt;/h4&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;QTcpSocket *socket;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h4 id=&quot;3接收连接并触发信号槽函数处理连接&quot;&gt;3、接收连接并触发信号槽函数处理连接&lt;/h4&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#include &quot;widget.h&quot;
#include &quot;ui_widget.h&quot;

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui-&amp;gt;setupUi(this);

    server = new QTcpServer;    //创建服务器对象
    //不需要绑定
    server-&amp;gt;listen(QHostAddress::AnyIPv4, PORT);    //监听
    //客户端发起连接,server发出信号,创建槽函数接收到信号后进行处理
    connect(server, &amp;amp;QTcpServer::newConnection, this, &amp;amp;Widget::newTcpClientConnectSlot);
}

Widget::~Widget()
{
    delete ui;
}

//槽函数实现，处理接收到的客户端连接
void Widget::newTcpClientConnectSlot()
{
    //建立TCP连接
    QTcpSocket *socket = server-&amp;gt;nextPendingConnection();
    //获取客户端地址(QHostAddress类型，显示出来需要转换成QString类型)和端口号(quint16类型，需要转换成QString类型)
    //socket-&amp;gt;peerAddress();
    //socket-&amp;gt;peerPort();

    ui-&amp;gt;ipLineEdit-&amp;gt;setText(socket-&amp;gt;peerAddress().toString());
    ui-&amp;gt;portLineEdit-&amp;gt;setText(QString::number(socket-&amp;gt;peerPort()));
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;qt启动新窗口&quot;&gt;Qt启动新窗口&lt;/h3&gt;
&lt;p&gt;qt里关闭当前窗口，跳转到另一个窗口。qt–&amp;gt;当前工程“界面文件”–&amp;gt;右键，添加新文件–&amp;gt;选择一个模板”Qt”–&amp;gt;Qt设计师界面类–&amp;gt;创建好新的窗口之后就可以编辑了（生成新的类及对应的文件）&lt;/p&gt;

&lt;h4 id=&quot;客户端-1&quot;&gt;客户端&lt;/h4&gt;
&lt;p&gt;链接：https://pan.baidu.com/s/1KPnGwo_xRRGCOux_44TGPA
提取码：r0u0&lt;/p&gt;

&lt;p&gt;1、如何启动新的界面（从一个界面跳转到另一个界面）
（1）隐藏当前界面
（2）仿照显示新的界面&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;//连接服务器成功，socket对象会发出信号
    connect(socket, &amp;amp;QTcpSocket::connected, [this]()
    {
       QMessageBox::information(this, &quot;连接提示&quot;, &quot;连接服务器成功&quot;);

       /*Qt启动新窗口*/
       this-&amp;gt;hide();  //隐藏之前界面

       chart *c = new chart(socket);        //在对空间创建chart对象
       c-&amp;gt;show();
    });
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;（3）将原界面（Widget对象）接收的内容通过socket传递给新界面(chart对象)
（4）往socket里写内容&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/*chart.h*/
#include &amp;lt;QTcpSocket&amp;gt;
class chart : public QWidget
{
    Q_OBJECT

public:
    //explicit chart(QWidget *parent = nullptr);
    /*修改chart构造函数，将socket传递给chart对象*/
    explicit chart(QTcpSocket *s, QWidget *parent = nullptr);
    ~chart();

private:
    Ui::chart *ui;

    QTcpSocket *socket;
};

/*chart.cpp*/
chart::chart(QTcpSocket *s, QWidget *parent) :
    QWidget(parent),
    ui(new Ui::chart)
{
    ui-&amp;gt;setupUi(this);

    socket = s;
}

//“取消”槽函数实现
void chart::on_clearButton_clicked()
{
    ui-&amp;gt;lineEdit-&amp;gt;clear();
}
//“发送”槽函数实现
void chart::on_sendButton_clicked()
{
    QByteArray ba;
    ba.append(ui-&amp;gt;lineEdit-&amp;gt;text());    //将内容转成QByteArray类型发送（写入socket）
    socket-&amp;gt;write(ba);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h4 id=&quot;服务端&quot;&gt;服务端&lt;/h4&gt;
&lt;p&gt;链接：https://pan.baidu.com/s/1jmNKSSH4crJq-pmrM8o8tA
提取码：9k6w&lt;/p&gt;

&lt;p&gt;（1）类里声明处理接收信息的槽函数&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/*widget.h*/
private slots:
    void newTcpClientConnectSlot();

    /*Qt启动新窗口 服务器端修改*/
    void clientInfoSlot();
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;（2）连接到客户端后，如果收到socket发出readyread信号，构建一个槽函数进行处理接收的信息&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;//槽函数实现，处理接收到的客户端连接
void Widget::newTcpClientConnectSlot()
{
    //建立TCP连接
    QTcpSocket *socket = server-&amp;gt;nextPendingConnection();
    //获取客户端地址(QHostAddress类型，显示出来需要转换成QString类型)和端口号(quint16类型，需要转换成QString类型)
    //socket-&amp;gt;peerAddress();
    //socket-&amp;gt;peerPort();

    ui-&amp;gt;ipLineEdit-&amp;gt;setText(socket-&amp;gt;peerAddress().toString());
    ui-&amp;gt;portLineEdit-&amp;gt;setText(QString::number(socket-&amp;gt;peerPort()));

    /*Qt启动新窗口 服务器端修改*/
    //服务器接收到客户端发送的信息，socket发出readyread信号，构建一个槽函数进行处理
    connect(socket, &amp;amp;QTcpSocket::readyRead, this, &amp;amp;Widget::clientInfoSlot);

}

/*Qt启动新窗口 服务器端修改*/
//槽函数实现，接收
void Widget::clientInfoSlot()
{
    //获取信号的发出者
    QTcpSocket *s = (QTcpSocket *)sender();

    ui-&amp;gt;lineEdit-&amp;gt;setText(QString(s-&amp;gt;readAll()));  //接收到的数据QByteArray类型，转成QString类型
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;qt多线程&quot;&gt;Qt多线程&lt;/h3&gt;
&lt;p&gt;Qt里把线程封装成了类，类似于C++。TCP服务器一旦接受一个客户端的连接，便建立一个线程。&lt;/p&gt;

&lt;p&gt;链接：https://pan.baidu.com/s/1he3nQvIJv-jkisgV3b7phg
提取码：ztnd&lt;/p&gt;

&lt;h4 id=&quot;1创建线程类生成头文件和源文件&quot;&gt;(1)创建线程类，生成头文件和源文件。&lt;/h4&gt;

&lt;p&gt;右键–&amp;gt;添加新文件–&amp;gt; C++ –&amp;gt; C++ Class (既会创建头文件也会创建源文件) –&amp;gt; 命名类名字myThread,基类继承于 QObject (还要手动继承 QThread)&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/*mythread.h*/
#ifndef MYTHREAD_H
#define MYTHREAD_H

#include &amp;lt;QObject&amp;gt;
#include &amp;lt;QThread&amp;gt;
/*Qt多线程*/
#include &amp;lt;QTcpSocket&amp;gt;
#include &amp;lt;QDebug&amp;gt;

class myThread : /*public QObject,*/ public QThread       //QThread本身继承于QObject类
{
    Q_OBJECT
public:
    explicit myThread(QTcpSocket *s);    //, QObject *parent = nullptr);    /*Qt多线程 传参*/
    /*Qt多线程 重写run()函数*/
    void run();                 //线程处理函数

signals:

public slots:
    void clientInfoSlot();      /*Qt多线程 槽函数，收到客户端TCP连接信号之后处理*/

private:
    QTcpSocket *socket;
};

#endif // MYTHREAD_H
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h4 id=&quot;2创建线程对象并运行线程&quot;&gt;(2)创建线程对象，并运行线程。&lt;/h4&gt;
&lt;p&gt;myThread类（自定义创建的）继承于QThread类，需要重写run()虚函数启动线程。&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/*widget.cpp*/
//槽函数实现，处理接收到的客户端连接
void Widget::newTcpClientConnectSlot()
{
    //建立TCP连接
    QTcpSocket *socket = server-&amp;gt;nextPendingConnection();
    //获取客户端地址(QHostAddress类型，显示出来需要转换成QString类型)和端口号(quint16类型，需要转换成QString类型)
    //socket-&amp;gt;peerAddress();
    //socket-&amp;gt;peerPort();

    ui-&amp;gt;ipLineEdit-&amp;gt;setText(socket-&amp;gt;peerAddress().toString());
    ui-&amp;gt;portLineEdit-&amp;gt;setText(QString::number(socket-&amp;gt;peerPort()));

    /*Qt启动新窗口 服务器端修改*/
    //服务器接收到客户端发送的信息，socket发出readyread信号，构建一个槽函数进行处理
    //connect(socket, &amp;amp;QTcpSocket::readyRead, this, &amp;amp;Widget::clientInfoSlot); /*Qt多线程 注释*/


    /*Qt多线程*/
    //启动线程
    myThread *t = new myThread(socket);    //创建线程对象。将widget类中的socket传递到myThread类中
    t-&amp;gt;start();                            //开始线程
}
-----------------------------------------
/*mythread.cpp*/
#include &quot;mythread.h&quot;

myThread::myThread(QTcpSocket *s)//,QObject *parent) //: QObject(parent)
{
    socket = s;
}

void myThread::run()
{
    //在线程里处理客户端TCP连接
    connect(socket, &amp;amp;QTcpSocket::readyRead, this, &amp;amp;myThread::clientInfoSlot);
}

//不能在其他类里面操作界面
void myThread::clientInfoSlot()
{
    qDebug() &amp;lt;&amp;lt; socket-&amp;gt;readAll();  /*Qt多线程 打印接收到的内容*/
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;（3）因为ui时widget类里面的，不能在myThread对象里操作ui界面输出内容。所以先通过qDebug()打印出来。&lt;/p&gt;

&lt;h3 id=&quot;qt自定义信号&quot;&gt;Qt自定义信号&lt;/h3&gt;
&lt;p&gt;对象是可以发出信号的，如果想通过信号传递一些数据，可以自定义信号。比如，qt线程收到tcp连接消息后，将数据发送到widget类，显示在界面上。（线程对象t –&amp;gt; 窗口对象w）&lt;/p&gt;

&lt;p&gt;链接：https://pan.baidu.com/s/1RjJLzYVu4MwAzAlNtJfEjg
提取码：u2jb&lt;/p&gt;

&lt;h4 id=&quot;1线程发出信号&quot;&gt;(1)线程发出信号&lt;/h4&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/*mythread.cpp*/
//不能在其他类里面操作界面，也就是不能再线程里操作widget类里的ui
void myThread::clientInfoSlot()
{
    //qDebug() &amp;lt;&amp;lt; socket-&amp;gt;readAll();  /*Qt多线程 打印接收到的内容*/

    /*自定义信号*/
    //将接收的数据读取
    QByteArray ba = socket-&amp;gt;readAll();
    emit sendToWidget(ba);              //发送信号,将接受的内容ba传递过去
}

/*mythread.h*/
class myThread : /*public QObject,*/ public QThread
{
    Q_OBJECT
public:
    explicit myThread(QTcpSocket *s);    //, QObject *parent = nullptr);    /*Qt多线程 传参*/
    /*Qt多线程 重写run()函数*/
    void run();

signals:
    /*自定义信号*/
    void sendToWidget(QByteArray b);    //自定义信号，信号也是函数

public slots:
    void clientInfoSlot();      /*Qt多线程 槽函数，收到客户端TCP连接信号之后处理*/

private:
    QTcpSocket *socket;
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h4 id=&quot;2界面接收线程信号&quot;&gt;(2)界面接收线程信号&lt;/h4&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/*widget.cpp*/
//槽函数实现，处理接收到的客户端连接
void Widget::newTcpClientConnectSlot()
{
    //建立TCP连接
    QTcpSocket *socket = server-&amp;gt;nextPendingConnection();
    //获取客户端地址(QHostAddress类型，显示出来需要转换成QString类型)和端口号(quint16类型，需要转换成QString类型)
    //socket-&amp;gt;peerAddress();
    //socket-&amp;gt;peerPort();

    ui-&amp;gt;ipLineEdit-&amp;gt;setText(socket-&amp;gt;peerAddress().toString());
    ui-&amp;gt;portLineEdit-&amp;gt;setText(QString::number(socket-&amp;gt;peerPort()));

    /*Qt启动新窗口 服务器端修改*/
    //服务器接收到客户端发送的信息，socket发出readyread信号，构建一个槽函数进行处理
    //connect(socket, &amp;amp;QTcpSocket::readyRead, this, &amp;amp;Widget::clientInfoSlot); /*Qt多线程*/


    /*Qt多线程*/
    //启动线程
    myThread *t = new myThread(socket);    //将widget类中的socket传递到myThread类中
    t-&amp;gt;start();

    /*自定义信号*/
    //接受线程信号并创建槽函数处理
    connect(t, &amp;amp;myThread::sendToWidget, this, &amp;amp;Widget::threadSlot);
}

/*自定义信号*/
//处理线程信息的槽函数
void Widget::threadSlot(QByteArray b)
{
    ui-&amp;gt;lineEdit-&amp;gt;setText(QString(b));
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;mysql数据库&quot;&gt;MySQL数据库&lt;/h3&gt;
&lt;h4 id=&quot;win10安装mysql&quot;&gt;Win10安装MySQL&lt;/h4&gt;
&lt;p&gt;参考另一篇博客。&lt;/p&gt;

&lt;h4 id=&quot;mysql创建表&quot;&gt;MySql创建表&lt;/h4&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#开启mysql windows/linux
net start nysql / service mysql start
#以root用户登录mysql，也可以用其他创建的用户登录
mysql -u root -p
输入密码
#创建数据
//创建数据
create database mydatabase;
//创建表
use mydatabase;
create table student (
	id integer unsigned primary key,
	name varchar(16) not null,
	birth date
)charset utf8;
//查看表
select * from student;
//插入数据
insert into student values (1, &quot;Tom&quot;, &quot;1999-9-9&quot;);

describe student;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;qt连接mysql&quot;&gt;Qt连接mysql&lt;/h4&gt;
&lt;h5 id=&quot;建立qt工程&quot;&gt;建立Qt工程&lt;/h5&gt;
&lt;p&gt;New Project –&amp;gt; Application –&amp;gt; Qt Widgets Application –&amp;gt; choose –&amp;gt; 命名”mysql” –&amp;gt; 选择类型 “QWidget” –&amp;gt;一直点击下一步–&amp;gt;完成。&lt;/p&gt;

&lt;h5 id=&quot;创建ui界面&quot;&gt;创建ui界面&lt;/h5&gt;
&lt;p&gt;Lable + Line Edit  –&amp;gt; 学号 **  （水平布局）&lt;/p&gt;

&lt;p&gt;Lable + Line Edit  –&amp;gt; 姓名 **  （水平布局）&lt;/p&gt;

&lt;p&gt;Lable + Line Edit  –&amp;gt; 电话 **  （水平布局）&lt;/p&gt;

&lt;p&gt;Push Button  –&amp;gt; 插入	//插入数据&lt;/p&gt;

&lt;p&gt;Push Button  –&amp;gt; 查询	//查询数据，qDebug打印出来即可&lt;/p&gt;

&lt;h5 id=&quot;qt工程加入sql&quot;&gt;Qt工程加入sql&lt;/h5&gt;
&lt;p&gt;(1) mysql.pro –&amp;gt; QT       += core gui sql&lt;/p&gt;

&lt;p&gt;(2) 头文件中创建数据库对象
#include &lt;QSqlDatabase&gt;  //包含mysql库
#include &lt;QMessageBox&gt;
#include &lt;QSqlQuery&gt;
#include &lt;QDebug&gt;&lt;/QDebug&gt;&lt;/QSqlQuery&gt;&lt;/QMessageBox&gt;&lt;/QSqlDatabase&gt;&lt;/p&gt;

&lt;p&gt;private:
    //创建数据库对象
    QSqlDatabase db;&lt;/p&gt;

&lt;p&gt;(3) .cpp 源文件&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#include &quot;widget.h&quot;
#include &quot;ui_widget.h&quot;

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui-&amp;gt;setupUi(this);

    //连接数据库
    db = QSqlDatabase::addDatabase(&quot;QMYSQL&quot;);    //加载MYSQL数据库驱动

    db.setDatabaseName(&quot;mydatabase&quot;);           //数据库名字，已提前在mysql中创建好的'create database mydatabase;'
    db.setHostName(&quot;localhost&quot;);                //连接数据库所在主机，此处是本地数据库本地连接
    db.setUserName(&quot;root&quot;);                     //数据库用户名
    //db.setPassword(&quot;123456&quot;);                 //数据库密码

    //打开数据库
    if(db.open())
    {
        //设置提示，需包含头文件 #include &amp;lt;QMessageBox&amp;gt;
        QMessageBox::information(this, &quot;连接提示&quot;, &quot;连接成功&quot;);
    }
    else
    {
        QMessageBox::warning(this, &quot;连接提示&quot;, &quot;连接失败&quot;);
    }

}

Widget::~Widget()
{
    delete ui;
}


void Widget::on_insertPushButton_clicked()
{
    QString id = ui-&amp;gt;idLineEdit-&amp;gt;text();
    QString name = ui-&amp;gt;nameLineEdit-&amp;gt;text();
    QString birth = ui-&amp;gt;lineEdit_2-&amp;gt;text();

    //QString sql = QString(&quot;insert into student values (1, &quot;Tom&quot;, &quot;1999-9-9&quot;);&quot;)
    QString sql = QString(&quot;insert into student values (%1, '%2', '%3');&quot;).arg(id).arg(name).arg(birth);

    //插入，建立一个操作数据库的对象
    QSqlQuery query;
    if(query.exec(sql))
    {
        QMessageBox::information(this, &quot;插入提示&quot;, &quot;插入成功&quot;);
    }
    else
    {
        QMessageBox::information(this, &quot;插入提示&quot;, &quot;插入失败&quot;);
    }

}

void Widget::on_findPushButton_clicked()
{
    QSqlQuery query;
    query.exec(&quot;select * from student;&quot;);
    while (query.next())
    {
        //将查询的结果打印出来
        qDebug() &amp;lt;&amp;lt; query.value(0);
        qDebug() &amp;lt;&amp;lt; query.value(1);
        qDebug() &amp;lt;&amp;lt; query.value(2);
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;问题：解决问题 Qt + MySql：”QSqlDatabase: QMYSQL driver not loaded&lt;/p&gt;

&lt;p&gt;https://blog.csdn.net/sigmarising/article/details/80664639&lt;/p&gt;

&lt;p&gt;也可以参考另一篇博客“QT使用相关的QAQ”。&lt;/p&gt;

&lt;h3 id=&quot;qtableview&quot;&gt;QTableView&lt;/h3&gt;
&lt;h4 id=&quot;qt连接远程数据库&quot;&gt;Qt连接远程数据库&lt;/h4&gt;
&lt;p&gt;1、创建Widget工程&lt;/p&gt;

&lt;p&gt;2、修改工程参数&lt;/p&gt;

&lt;p&gt;QT       += core gui sql  // .pro 工程文件中加入sql&lt;/p&gt;

&lt;p&gt;//.h 头文件包含库
#include &lt;QSqlDatabase&gt;&lt;/QSqlDatabase&gt;&lt;/p&gt;

&lt;p&gt;//widget.cpp 源文件&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#include &quot;widget.h&quot;
#include &quot;ui_widget.h&quot;

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui-&amp;gt;setupUi(this);

    //连接远程数据库
    QSqlDatabase db = QSqlDatabase::addDatabase(&quot;QMYSQL&quot;);

    //设置连接属性，数据库ip、用户名、密码
    db.setHostName(&quot;106.55.**.**&quot;);  //远程ubuntu云服务器ip
    db.setDatabaseName(&quot;mydatabase&quot;);
    db.setUserName(&quot;test&quot;);
    db.setPassword(&quot;test&quot;);

    if(db.open())
    {
        QMessageBox::information(this, &quot;连接提示&quot;, &quot;连接成功&quot;);
    }
    else
    {
        QMessageBox::warning(this, &quot;连接提示&quot;, &quot;连接失败&quot;);
    }
}

Widget::~Widget()
{
    delete ui;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;3、mysql数据库操作&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#mysql创建用户，%表示所有用户都可以登录
create user &quot;test&quot;@&quot;%&quot; identified by &quot;test&quot;;
#授权该用户的操作权限
grant select, insert, create on *.* to &quot;test&quot;@&quot;%&quot;;
#exit退出，然后使用test用户登录
mysql -u test -p
#密码为test
#创建一个数据库
create database mydatabase;
#使用创建的数据库
use mydatabase;
#在数据库中创建一张表
create table student (
	id integer unsigned primary key,
	name varchar(16) not null,
	birth date
)charset utf8;
#在表中插入一些数据
insert into student values (1, &quot;tom&quot;, &quot;1999-9-9&quot;);
insert into student values (2, &quot;jack&quot;, &quot;1999-9-9&quot;);
insert into student values (3, &quot;chen&quot;, &quot;1993-07-22&quot;);

select * from student;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;4、Qt插件使用&lt;/p&gt;

&lt;p&gt;widget.ui –&amp;gt; Item Views –&amp;gt; Table View  //qt里面自动格式化显示表格的插件&lt;/p&gt;

&lt;p&gt;//需要包含头文件 #include &lt;QSqlTableModel&gt; 以及 创建模型对象&lt;/QSqlTableModel&gt;&lt;/p&gt;

&lt;p&gt;连接数据库成功之后，通过Table View插件，查询数据库表&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;...
if(db.open())
{
    QMessageBox::information(this, &quot;连接提示&quot;, &quot;连接成功&quot;);

    //新建模型对象
    m = new QSqlTableModel;
    m-&amp;gt;setTable(&quot;student&quot;);
    ui-&amp;gt;tableView-&amp;gt;setModel(m);     //将数据模型m对象与ui界面模型tableView连接起来


}
else
...

//ui上添加了一个“查询” PushButton
void Widget::on_pushButton_clicked()
{
    m-&amp;gt;select();  //model模型对象的成员函数select查询
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Wed, 29 Dec 2021 00:00:00 +0000</pubDate>
        <link>https://jinbao1chen.github.io/2021/12/Qt/</link>
        <guid isPermaLink="true">https://jinbao1chen.github.io/2021/12/Qt/</guid>
        
        <category>工具，Qt</category>
        
        
      </item>
    
      <item>
        <title>Libevent 信号</title>
        <description>&lt;h2 id=&quot;note&quot;&gt;Note&lt;/h2&gt;
&lt;p&gt;利用Libevent创建监听集合，将信号事件绑定并放入监听集合中，一旦监听到有信号发生便会触发&lt;/p&gt;

&lt;h2 id=&quot;信号事件&quot;&gt;信号事件&lt;/h2&gt;

&lt;p&gt;注意：编译的时候要加libevent库, gcc 信号.c -o 信号 -levent&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/****************************************************************************
Libevent 也可以监听信号
  //创建事件集合的方法：使用event_init函数 或者 直接使用 event_base_new
  struct event_base *event_init(void)
  {
	struct event_base *base = event_base_new_with_config(NULL);

	if (base == NULL) {
		event_errx(1, &quot;%s: Unable to construct event_base&quot;, __func__);
		return NULL;
	}

	current_base = base;

	return (base);
  }

  struct event_base *event_base_new(void)
  {
	struct event_base *base = NULL;
	struct event_config *cfg = event_config_new();
	if (cfg) {
		base = event_base_new_with_config(cfg);
		event_config_free(cfg);
	}
	return base;
  }

  //把事件和集合绑定，event_set默认把事件与全局变量集合绑定，而event_assign则可以把事件ev和指定current_base集合绑定
  void event_set(struct event *ev, evutil_socket_t fd, short events,
	  void (*callback)(evutil_socket_t, short, void *), void *arg)
  {
	int r;
	r = event_assign(ev, current_base, fd, events, callback, arg);
	EVUTIL_ASSERT(r == 0);
  }
*******************************************************************************/

#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;signal.h&amp;gt;
#include &amp;lt;event.h&amp;gt;

int signal_count = 0;
void signal_handler(evutil_socket_t fd, short events, void *arg)
{
	struct event *ev = (struct event *)arg;
	printf(&quot;收到信号 %d \n&quot;, fd);

	signal_count++;
	if(signal_count &amp;gt;= 2)
	{
		//把事件从集合中删除
		event_del(ev);
	}
}

int main()
{
	//创建事件集合，ps:记得释放集合
	struct event_base *base = event_base_new();

	//创建事件
	struct event ev;

	//将事件和信号绑定
	//参数：事件 集合 信号(crtl+c) 类型 回调函数 回调函数入参(把集合传给回调，用于达到一定条件终止循环)
	event_assign(&amp;amp;ev, base, SIGINT, EV_SIGNAL | EV_PERSIST, signal_handler, &amp;amp;ev);

	//事件添加到集合中
	event_add(&amp;amp;ev, NULL);

	//监听集合(自己创建的集合，不使用event_dispatch默认监听全局变量集合)
	//event_dispatch();
	event_base_dispatch(base);

	//释放集合
	event_base_free(base);

	return 0;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Wed, 29 Dec 2021 00:00:00 +0000</pubDate>
        <link>https://jinbao1chen.github.io/2021/12/Libevent%E4%BF%A1%E5%8F%B7/</link>
        <guid isPermaLink="true">https://jinbao1chen.github.io/2021/12/Libevent%E4%BF%A1%E5%8F%B7/</guid>
        
        <category>C，网络通信</category>
        
        
      </item>
    
      <item>
        <title>Libevent IO事件</title>
        <description>&lt;h2 id=&quot;note&quot;&gt;Note&lt;/h2&gt;
&lt;p&gt;利用Libevent创建监听集合，将管道的读端与事件绑定并放入监听集合中，在管道另一端写内容，监听集合一旦监听到就会自动触发读取管道内内容&lt;/p&gt;

&lt;h2 id=&quot;管道服务端&quot;&gt;管道服务端&lt;/h2&gt;

&lt;p&gt;注意：编译的时候要加libevent库, gcc 管道服务端.c -o 管道服务端 -levent&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// ##############################################################################################
	//初始化事件（把fd和事件ev绑定） 参数：关联的文件描述符 事件类型 回调函数 回调函数参数
	/*******函数原型 BEGIN********
	struct event_base *event_init(void);

	void
	event_set(struct event *ev, evutil_socket_t fd, short events, void (*callback)(evutil_socket_t, short, void *), void *arg)
	参数说明：
	** this flag to event_for new()/event_assign() to get a timeout.
	//#define EV_TIMEOUT	0x01
	** Wait for a socket or FD to become readable
	//#define EV_READ		0x02
	** Wait for a socket or FD to become writeable
	//#define EV_WRITE	0x04
	** Wait for a POSIX signal to be raised
	//#define EV_SIGNAL	0x08
	**
 	* Persistent event: won't get removed automatically when activated.
 	*
 	* When a persistent event with a timeout becomes activated, its timeout
 	* is reset to 0.
 	**
	#define EV_PERSIST	0x10
	** Select edge-triggered behavior, if supported by the backend. **
	#define EV_ET		0x20
	**
 	* If this option is provided, then event_del() will not block in one thread
 	* while waiting for the event callback to complete in another thread.
 	*
 	* To use this option safely, you may need to use event_finalize() or
 	* event_free_finalize() in order to safely tear down an event in a
 	* multithreaded application.  See those functions for more information.
 	**
	#define EV_FINALIZE     0x40
	**
 	* Detects connection close events.  You can use this to detect when a
 	* connection has been closed, without having to read all the pending data
 	* from a connection.
 	*
 	* Not all backends support EV_CLOSED.  To detect or require it, use the
 	* feature flag EV_FEATURE_EARLY_CLOSE.
	**
	#define EV_CLOSED	0x80

	********函数原型 END*********/
// ##############################################################################################

#include &amp;lt;sys/types.h&amp;gt;
#include &amp;lt;sys/stat.h&amp;gt;
#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;event.h&amp;gt;
#include &amp;lt;sys/types.h&amp;gt;
#include &amp;lt;sys/stat.h&amp;gt;
#include &amp;lt;fcntl.h&amp;gt;
#include &amp;lt;unistd.h&amp;gt;

/********回调函数 BEGIN ******
原型：void (*callback)(evutil_socket_t, short, void *)
*********回调函数 END ********/
void fifo_read(evutil_socket_t fd, short events, void *arg)
{
	char buf[32] = {0};
	int ret = read(fd, buf, sizeof(buf));
	if(-1 == ret)
	{
		perror(&quot;read err&quot;);
		exit(1);
	}

	printf(&quot;从管道内读取 %s\n&quot;, buf);
}

int main()
{
	int ret = mkfifo(&quot;fifo.temp&quot;,00700); //创建管道，成功返回1失败返回0；参数1管道文件，参数2权限
	if(-1 == ret)
	{
		perror(&quot;mkfifo&quot;);
		exit(1);
	}

	int fd = open(&quot;fifo.temp&quot;, O_RDONLY); //打开管道，设置只读取
	if(-1 == fd)
	{
		perror(&quot;open err&quot;);
		exit(1);
	}

	/********** 1、把管道fd与事件绑定 2、将事件加入到事件集合 3、**********/
	//创建事件
	struct event ev;

	//初始化事件集合
	event_init();

	event_set(&amp;amp;ev, fd, EV_READ|EV_PERSIST, fifo_read, NULL);  //EV_PERSIST 设置即使集合中没有事件监听，也不会退出

	//把事件添加到集合中
	event_add(&amp;amp;ev, NULL);

	//开启监听，死循环, 如果集合中没有事件监听则返回
	event_dispatch();
	return 0;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;管道客户端&quot;&gt;管道客户端&lt;/h2&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;sys/types.h&amp;gt;
#include &amp;lt;sys/stat.h&amp;gt;
#include &amp;lt;fcntl.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;unistd.h&amp;gt;

int main()
{
	//创建有名管道
	//int ret = mkfifo(&quot;fifo.temp&quot;, 00400 | 00200);
	//if(-1 == ret)
	//{
	//	perror(&quot;mkfifo err&quot;);
	//	exit(1);
	//}

	//默认是阻塞的
	int fd = open(&quot;fifo.temp&quot;, O_WRONLY);
	if(-1 == fd)
	{
		perror(&quot;open err&quot;);
		exit(1);
	}

	int ret;
	char buf[32] = {0};
	while(1)
	{
		scanf(&quot;%s&quot; ,buf);
		ret = write(fd, buf, strlen(buf));
		if(-1 == ret)
		{
			perror(&quot;write&quot;);
			exit(1);
		}

		if(!strcmp(buf, &quot;bye&quot;))
		{
			break;
		}

		memset(buf, 0, sizeof(buf));
	}
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Tue, 28 Dec 2021 00:00:00 +0000</pubDate>
        <link>https://jinbao1chen.github.io/2021/12/Libevent%E7%AE%A1%E9%81%93/</link>
        <guid isPermaLink="true">https://jinbao1chen.github.io/2021/12/Libevent%E7%AE%A1%E9%81%93/</guid>
        
        <category>C，网络通信</category>
        
        
      </item>
    
      <item>
        <title>链表</title>
        <description>&lt;h2 id=&quot;链表&quot;&gt;链表&lt;/h2&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# ifndef _NODE_H_
# define _NODE_H_

//定义一个Node链表类型结构体
typedef struct _node{
    int value;            //数据
    struct _node *next;   //指针
} Node;

#endif
---

## 链表结尾插入元素
---
#include &quot;node.h&quot;
#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;

//自己定义的数据结构
typedef struct _list{
	Node * head;
} List;

void add(List* pList, int number);

int main(int argc, char const argv[]) {
	List list;
	Node * head = NULL;
	int number;
	do {
		printf(&quot;Input: &quot;);
		scanf(&quot;%d&quot;,number);
		if( number != -1)
		{
			//add to linked-list
			add(&amp;amp;list, number);

		}

	} while (number != -1);
	return 0;
}

void add(List* pList, int number)
{
	Node * p = (Node*)malloc(sizeof(Node));
	p-&amp;gt;value = number;
	p-&amp;gt;next = NULL;

	//find the last
	Node * last = pList-&amp;gt;head;
	if(last)
	{
		while(last-&amp;gt;next)
		{
			last = last-&amp;gt;next;
		}
		//attach
		last-&amp;gt;next = p;
	}
	else
	{
		pList-&amp;gt;head = p;
	}
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;//省略遍历才能找到链表末尾&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#include &quot;node.h&quot;
#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;

typedef struct _list{
	Node * head;
	Node * tail;
} List;

void add(List* pList, int number);

int main(int argc, char const argv[]) {
	List list;
	Node * head = NULL;
	int number;
	do {
		printf(&quot;Input: &quot;);
		scanf(&quot;%d&quot;,number);
		if( number != -1)
		{
			//add to linked-list
			add(&amp;amp;list, number);

		}

	} while (number != -1);
	return 0;
}

void add(List* pList, int number)
{
	Node * p = (Node*)malloc(sizeof(Node));
	p-&amp;gt;value = number;
	p-&amp;gt;next = NULL;

	//find the last
//	Node * last = pList-&amp;gt;head;
//	if(last)
//	{
//		while(last-&amp;gt;next)
//		{
//			last = last-&amp;gt;next;
//		}
//		//attach
//		last-&amp;gt;next = p;
//	}
//	else
//	{
//		pList-&amp;gt;head = p;
//	}
	//How to write tail-&amp;gt;head ?
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;打印链表内容&quot;&gt;打印链表内容&lt;/h2&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#include &quot;node.h&quot;
#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;

typedef struct _list{
	Node * head;
//	Node * tail;
} List;

void add(List* pList, int number);
void print(List *pList);

int main(int argc, char const argv[]) {
	List list;
	Node * head = NULL;
	int number;
	do {
		printf(&quot;Input: &quot;);
		scanf(&quot;%d&quot;,number);
		if( number != -1)
		{
			//add to linked-list
			add(&amp;amp;list, number);

		}

	} while (number != -1);

	print(&amp;amp;list);

	return 0;
}

void add(List* pList, int number)
{
	Node * p = (Node*)malloc(sizeof(Node));
	p-&amp;gt;value = number;
	p-&amp;gt;next = NULL;

	//find the last
	Node * last = pList-&amp;gt;head;
	if(last)
	{
		while(last-&amp;gt;next)
		{
			last = last-&amp;gt;next;
		}
		//attach
		last-&amp;gt;next = p;
	}
	else
	{
		pList-&amp;gt;head = p;
	}
}

void print(List *pList)
{
	Node * p;
	for(p=pList-&amp;gt;head; p ; p=p-&amp;gt;next)
	{
		printf(&quot;%d\t&quot;,p-&amp;gt;value);
	}
	printf(&quot;\n&quot;);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;删除指定链表元素--清除链表&quot;&gt;删除指定链表元素 &amp;amp; 清除链表&lt;/h2&gt;
&lt;p&gt;输入一个数字并在链表中找到该数字且删除&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#include &quot;node.h&quot;
#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;

typedef struct _list{
	Node * head;
//	Node * tail;
} List;

int isFound;

void add(List* pList, int number);
void print(List *pList);

int main(int argc, char const argv[]) {
	List list;
	Node * head = NULL;
	int number;
	do {
		printf(&quot;Input: &quot;);
		scanf(&quot;%d&quot;,number);
		if( number != -1)
		{
			//add to linked-list
			add(&amp;amp;list, number);

		}

	} while (number != -1);

	print(&amp;amp;list);

	//find element
	Node * p;
	for(p=list.head; p ; p=p-&amp;gt;next)
	{
		if(p-&amp;gt;value == number)
		{
			printf(&quot;找到了\n&quot;);
		}
		isFound = 1;
		break;
	}
	if(!isFound)
	{
		printf(&quot;没有找到\n&quot;);
	}

	//find element and delete it
	Node *q;
	for(q=NULL,p=list.head; p; q=p, p=p-&amp;gt;next)
	{
		if(p-&amp;gt;value == number)
		{
			if(q)
			{
				q-&amp;gt;next = p-&amp;gt;next;
			}
			else
			{
				list.head = p-&amp;gt;next;
			}
			free(p);
			break;
		}
	}

	//delete all list
	for(p=head; p; p=q)
	{
		q=p-&amp;gt;next;
		free(p);
	}

	return 0;
}

void add(List* pList, int number)
{
	Node * p = (Node*)malloc(sizeof(Node));
	p-&amp;gt;value = number;
	p-&amp;gt;next = NULL;

	//find the last
	Node * last = pList-&amp;gt;head;
	if(last)
	{
		while(last-&amp;gt;next)
		{
			last = last-&amp;gt;next;
		}
		//attach
		last-&amp;gt;next = p;
	}
	else
	{
		pList-&amp;gt;head = p;
	}
}

void print(List *pList)
{
	Node * p;
	for(p=pList-&amp;gt;head; p ; p=p-&amp;gt;next)
	{
		printf(&quot;%d\t&quot;,p-&amp;gt;value);
	}
	printf(&quot;\n&quot;);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Sun, 21 Nov 2021 00:00:00 +0000</pubDate>
        <link>https://jinbao1chen.github.io/2021/11/%E9%93%BE%E8%A1%A8/</link>
        <guid isPermaLink="true">https://jinbao1chen.github.io/2021/11/%E9%93%BE%E8%A1%A8/</guid>
        
        <category>C</category>
        
        
      </item>
    
      <item>
        <title>网络爬虫-requests模块</title>
        <description>&lt;h2 id=&quot;requests模块&quot;&gt;requests模块&lt;/h2&gt;
&lt;p&gt;1、requests模块作用：发送HTTP请求，获取响应数据&lt;/p&gt;

&lt;p&gt;2、安装：pip/pip3 install requests 或 在pycharm安装, File–&amp;gt;Setting–&amp;gt;Project:xx–&amp;gt;Python Interpreter–&amp;gt;Package–&amp;gt; “+” » 输入 requests 直接安装即可。&lt;/p&gt;

&lt;p&gt;3、使用，发送get请求：（1）导入；（2）调用get方法，对目标URL发送请求&lt;/p&gt;

&lt;h2 id=&quot;响应对象&quot;&gt;响应对象&lt;/h2&gt;
&lt;p&gt;分类：&lt;/p&gt;

&lt;p&gt;源码      XX.text       str字符串&lt;/p&gt;

&lt;p&gt;二进制    .content      bytes&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;例子：
# 导入
import requests

# 目标网址
url = 'http://www.baidu.com'

# 发出请求
response = requests.get(url)

# 设置（响应）解码格式
response.encoding = 'utf-8'

# 打印源码的str类型数据
print(response.text)

# print(response.encoding)

# response.content 是存储的bytes类型的响应源码，可以进行decode操作
print(response.content.decode()) #默认utf-8
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;发送带请求头headers的请求&quot;&gt;发送带请求头headers的请求&lt;/h2&gt;
&lt;p&gt;requests.get(url, headers={})&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;例子：
import requests

url = 'http://www.baidu.com'
response = requests.get(url)

# 构建请求头字典
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36'
}

# 发送带请求头的请求
response1 = requests.get(url, headers=headers)

print(len(response1.content.decode()))
print(response1.content.decode())
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;发送带参数的请求&quot;&gt;发送带参数的请求&lt;/h2&gt;
&lt;p&gt;1、url中直接带参数&lt;/p&gt;

&lt;p&gt;2、使用params参数：&lt;/p&gt;

&lt;p&gt;（1）构建参数字典&lt;/p&gt;

&lt;p&gt;（2）发送请求的时候设置参数字典&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# 知识点：掌握发送带参数的请求的方法

import requests

# 发送带参数的请求两种方法：（1）直接在url中加入参数

##############################################################################################
# # 第一种方法
# url = 'https://www.baidu.com/s?&amp;amp;wd=python'  # 通过删除法获得的url
#
# # 构建请求头字典
# headers = {
#     'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36'
# }
#
# response = requests.get(url,headers=headers)
#
# # 验证
# with open('baidu.html','wb') as f:
#     f.write(response.content)

###############################################################################################
# 第二种方法：通过参数params携带参数字典
# 1、构建参数字典
# 2、发送请求的时候设置参数字典
url = 'https://www.baidu.com/s?'

# 构建请求头字典
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36'
}

# 构建参数字典
data = {
    'wd':'python'
}

response = requests.get(url,headers=headers,params=data)

# 验证
with open('baidu1.html','wb') as f:
    f.write(response.content)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;在headers中携带cookies&quot;&gt;在headers中携带cookies&lt;/h2&gt;
&lt;p&gt;方法同ua&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# 知识点：掌握headers中携带cookies
# 对于登录，需要cookies保持登录状态。

import requests

url = 'https://github.com/jinbao1chen'

headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36',
    'cookie': '_octo=GH1.1.1844290650.1631717716; tz=Asia%2FShanghai; _device_id=85f612f7b15e03a1c45b200d88608722; has_recent_activity=1; user_session=46oFNc-72H_aOTyzPXbbWHoffxbh8W8THzEcFxIrQdzXKIs9; __Host-user_session_same_site=46oFNc-72H_aOTyzPXbbWHoffxbh8W8THzEcFxIrQdzXKIs9; tz=Asia%2FShanghai; color_mode=%7B%22color_mode%22%3A%22auto%22%2C%22light_theme%22%3A%7B%22name%22%3A%22light%22%2C%22color_mode%22%3A%22light%22%7D%2C%22dark_theme%22%3A%7B%22name%22%3A%22dark%22%2C%22color_mode%22%3A%22dark%22%7D%7D; logged_in=yes; dotcom_user=jinbao1chen; _gh_sess=NgmBBHrLFMpZrWTqbdfIKFouWCUC77eL%2Fd5vmgL3SfOjrXPwnks8sKrgLfx%2FN%2Bu77Rqvv%2FZ6fdpP881nVG6ebFlBl2qnhv3vKWVhW8wNHhdee1JcjiIdCHlpVe9f%2B6m6U0pgA8a3NQYEalEkCw4mNePnAv2MNvpyQJasxhd4UTqPeiKcmNLffllvDIRRHpNmn9TE3qYCbTY8Z14jU39XH7qmcJ81uwZ6Z0juhOHwvfkLtpqoJybkSaUhEORCGpdULZX%2FaZBdkcRZXdnivgOJ5%2FxapuxiaM1gbzofGjfP%2FZKna2BZCTXy1%2BlnY21wcQkI4cT3JDS40O%2BAjEq%2FNEFlgQH3t6oAoPIdiukLvC0F27BC2HZehqmcUfLjLz%2BV%2FQ2G%2FJbLAJ%2F%2BpJjS0hmoHL%2Fmp7EjNLOF0oU%2FGyJoonIk0VW0NaA%2FS9LxunBCHVfej23wolzfh9KYbE37kCDY3nYz266NP0eK57Q4rfcCvlDsb2uClpmSJIuanx%2BZBI2Lr9LLyYbmidS25X8MfAEueTzQXSNOh02BMdbJbEd87%2BHPIOqmMvcGDJ3%2F%2BehOvbDJJgPsOS3QpLhhc5zxrE7L9GkTwOAfgRQi3OkhvRobrm1%2FSwhg24brVnVlf4Xn%2BxDivc5M%2FbXoDsAmeqjC77d210r%2BhN6KCsTrR5UnYQsnMD4V4QlvTtgpgxWIV1M27VeXHl0LGIoIJRdbWEKmDxX4IgoVZD7XRJov%2BOvZ52OV0xjoxMFFJfyf4vfKEEQTrB1BNM8v61foCFJLLGGwekrgW6Pn4vIOiF5lMYzYiWQyzO2a22%2BLAIoqxYk4wRBblNIB7v6v3Ro%2Fm%2FeR0HZMNTKGtG0aBJembSVF6ywH6EDqgn%2F%2F1EC7ICslk4vrGWlUig2b%2F%2FBIFx2fekfQZ3N0wkgwxtgG4f03LujVyLnDlPulLw%3D%3D--IvqopqaZJvu9dWfC--JlES5vUzbHS9Z34fitlTEg%3D%3D'
}

response = requests.get(url,headers=headers)

# 验证
with open('github.html','wb')as f:
    f.write(response.content)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;使用cookies参数保持会话&quot;&gt;使用cookies参数保持会话&lt;/h2&gt;
&lt;p&gt;1、构建cookies字典&lt;/p&gt;

&lt;p&gt;2、在请求的时候将cookies字典赋值给cookies参数：requests.get(url, cookies)&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# 知识点：掌握cookies参数的使用
# 使用cookies参数保持会话：构建cookies字典；在请求的时候将cookies字典赋值给cookies参数，requests.get(url,cookies)

import requests

url = 'https://github.com/jinbao1chen'

headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36'
}

# 构建cookies字典
temp = '_octo=GH1.1.1844290650.1631717716; tz=Asia%2FShanghai; _device_id=85f612f7b15e03a1c45b200d88608722; has_recent_activity=1; user_session=46oFNc-72H_aOTyzPXbbWHoffxbh8W8THzEcFxIrQdzXKIs9; __Host-user_session_same_site=46oFNc-72H_aOTyzPXbbWHoffxbh8W8THzEcFxIrQdzXKIs9; tz=Asia%2FShanghai; color_mode=%7B%22color_mode%22%3A%22auto%22%2C%22light_theme%22%3A%7B%22name%22%3A%22light%22%2C%22color_mode%22%3A%22light%22%7D%2C%22dark_theme%22%3A%7B%22name%22%3A%22dark%22%2C%22color_mode%22%3A%22dark%22%7D%7D; logged_in=yes; dotcom_user=jinbao1chen; _gh_sess=NgmBBHrLFMpZrWTqbdfIKFouWCUC77eL%2Fd5vmgL3SfOjrXPwnks8sKrgLfx%2FN%2Bu77Rqvv%2FZ6fdpP881nVG6ebFlBl2qnhv3vKWVhW8wNHhdee1JcjiIdCHlpVe9f%2B6m6U0pgA8a3NQYEalEkCw4mNePnAv2MNvpyQJasxhd4UTqPeiKcmNLffllvDIRRHpNmn9TE3qYCbTY8Z14jU39XH7qmcJ81uwZ6Z0juhOHwvfkLtpqoJybkSaUhEORCGpdULZX%2FaZBdkcRZXdnivgOJ5%2FxapuxiaM1gbzofGjfP%2FZKna2BZCTXy1%2BlnY21wcQkI4cT3JDS40O%2BAjEq%2FNEFlgQH3t6oAoPIdiukLvC0F27BC2HZehqmcUfLjLz%2BV%2FQ2G%2FJbLAJ%2F%2BpJjS0hmoHL%2Fmp7EjNLOF0oU%2FGyJoonIk0VW0NaA%2FS9LxunBCHVfej23wolzfh9KYbE37kCDY3nYz266NP0eK57Q4rfcCvlDsb2uClpmSJIuanx%2BZBI2Lr9LLyYbmidS25X8MfAEueTzQXSNOh02BMdbJbEd87%2BHPIOqmMvcGDJ3%2F%2BehOvbDJJgPsOS3QpLhhc5zxrE7L9GkTwOAfgRQi3OkhvRobrm1%2FSwhg24brVnVlf4Xn%2BxDivc5M%2FbXoDsAmeqjC77d210r%2BhN6KCsTrR5UnYQsnMD4V4QlvTtgpgxWIV1M27VeXHl0LGIoIJRdbWEKmDxX4IgoVZD7XRJov%2BOvZ52OV0xjoxMFFJfyf4vfKEEQTrB1BNM8v61foCFJLLGGwekrgW6Pn4vIOiF5lMYzYiWQyzO2a22%2BLAIoqxYk4wRBblNIB7v6v3Ro%2Fm%2FeR0HZMNTKGtG0aBJembSVF6ywH6EDqgn%2F%2F1EC7ICslk4vrGWlUig2b%2F%2FBIFx2fekfQZ3N0wkgwxtgG4f03LujVyLnDlPulLw%3D%3D--IvqopqaZJvu9dWfC--JlES5vUzbHS9Z34fitlTEg%3D%3D'

# 切割成键值对
# 1、稳妥方案
# cookie_list = temp.split('; ')  #以 分号+空格 为标记分割
# cookies = {}   #创建一个cookies字典
#
# for cookie in cookie_list:
#     cookies[cookie.split('=')[0]] = cookie.split('=')[-1]  #获取等号右边的值

# 2、优化方案(字典推导式写得特别6)
cookie_list = temp.split('; ')
cookies = {cookie.split('=')[0]: cookie.split('=')[-1] for cookie in cookie_list}

print(cookies)

response = requests.get(url,headers=headers,cookies=cookies)

# 验证
with open('github_with_cookies.html','wb')as f:
    f.write(response.content)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# requests模块：cookiejar对象处理
# cookiejar对象转换为cookies字典的方法：1、转换方法 cookies_dict = requests.utils.dict_from_cookiejar(response.cookies)
# 2、其中 response.cookies 返回的就是cookiejar类型的对象 3、requests.utils.dict_from_cookiejar 函数返回cookies字典
# 4、requests.utils.cookiejar_from_dict 函数返回字典的cookiejar类型的对象，但会丢失域名

import requests

url = 'http://www.baidu.com'

response = requests.get(url)
print(response.cookies)

dict_cookies = requests.utils.dict_from_cookiejar(response.cookies)
print(dict_cookies)

jar_cookies = requests.utils.cookiejar_from_dict(dict_cookies)
print(jar_cookies)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;超时参数timeout的使用&quot;&gt;超时参数timeout的使用&lt;/h2&gt;
&lt;p&gt;requests.get(url, timeout=3)&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# timeout 参数的使用

import requests

url = 'https://twitter.com'

response = requests.get(url,timeout=3) #3秒连接不成功即返回失败，防止程序阻塞
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;代理&quot;&gt;代理&lt;/h2&gt;
&lt;p&gt;1、什么是代理：代理IP是一个ip,指向的是一个代理服务器,通常用作应对网站反爬&lt;/p&gt;

&lt;p&gt;2、分类：正向代理和反向代理，以知不知道最终服务器的地址为判断标准&lt;/p&gt;

&lt;p&gt;3、代理IP的分类：（1）按匿名度，透明、匿名、高匿 （2）协议，http、https、socks&lt;/p&gt;

&lt;p&gt;4、使用：requests.get(url, proxies=proxies)&lt;/p&gt;

&lt;p&gt;代理使用成功不会有任何报错，能成功获取响应；如果失败，要么卡滞，要么报错&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# 代理：是一个ip，指向的是一个代理服务器
# 正向代理和反向代理，以知不知道最终服务器的地址作为判断标准
# 代理分类：透明、匿名、高匿，服务器能否判断出代理为标准，使用高匿代理效果最好
# 协议分类：http、https、socks
# 用法：response = requests.get(url, proxies=proxies), proxies形式是字典，例如：
# proxies = { 'http' : 'http://12.34.56.79:9527',
#           'https' : 'http://12.34.56.79:9527' }
# 如果proxies字典中包含多个键值对，发送请求时将按照url地址的协议来选择使用响应的代理ip

# 代理使用成功不会有任何报错，能成功获取响应；如果失败，要么卡滞，要么报错

import requests

url = 'https://www.baidu.com/'

# 构建代理字典，代理从网上搜免费，但是需要甄别筛选
proxies = {
    'http': 'http://36.56.100.109:9999',
    # 'https': 'https://223.240.208.230:1133'
}

# response = requests.get(url)
response = requests.get(url, proxies=proxies)
print(response.text)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;ca认证&quot;&gt;CA认证&lt;/h2&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# 爬虫过程遇到 网站的CA证书没有经过认证，会导致连接不是私密链接，无法进入。解决：无视忽略CA证书

import requests

url = 'https://sam.huat.edu.cn:8443/selfservice'

response = requests.get(url, verify=False) # 直接添加参数，有警告但无碍

print(response.content)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;requests模块发送post请求&quot;&gt;requests模块发送post请求&lt;/h2&gt;
&lt;p&gt;1、实现方法：requests.post(url, data), data是一个字典&lt;/p&gt;

&lt;p&gt;2、post数据来源 «重点/难点»&lt;/p&gt;

&lt;p&gt;(1)固定值：           抓包比较不变值&lt;/p&gt;

&lt;p&gt;(2)输入值：           抓包比较根据自身变化值&lt;/p&gt;

&lt;p&gt;(3)预设值-静态文件：  需要提前从静态html中获取&lt;/p&gt;

&lt;p&gt;(4)预设值-发请求：    需要指定地址发送请求&lt;/p&gt;

&lt;p&gt;(5)在客户端生成的：   分析js，模拟生成数据&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# requests模块发送 post 请求
# 方法：response = requests.post(url,data), data 参数接收一个字典
# requests 模块发送post请求函数的其他参数和发送 get 请求的参数完全一致

import json
import sys
import requests

class King(object):

    def __init__(self,word):
        self.url = 'http://ifanyi.iciba.com/index.php?c=trans&amp;amp;m=fy&amp;amp;client=6&amp;amp;auth_user=key_ciba&amp;amp;sign=37218aa29f55fdcc'

        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36'
        }

        self.data = {
            'from': 'zh',
            'to': 'en',
            'q': word
        }

    def get_data(self):
        # 使用post发送一个请求
        reponse = requests.post(self.url, data=self.data, headers=self.headers)
        return reponse.content

    def data_param(self,data):
        # loads方法将json字符串转化成python字典
        dict_data = json.loads(data)
        print(dict_data['content']['out'])

    # 编写爬虫逻辑
    def run(self):
        # url
        # headers
        # data字典
            # post数据来源：（难点）
            # 1、固定值：        抓包比较不变值
            # 2、输入值：        抓包比较根据自身变化值
            # 3、预设值-静态文件： 需要提前从静态html中获取
            # 4、预设值-发请求：  需要对指定地址发送请求
            # 5、在客户端生成：   分析js，模拟生成数据
        # 发送请求获取响应
        reponse = self.get_data()
        # print(reponse)
        # 数据解析
        self.data_param(reponse)

if __name__=='__main__':
    # print(sys.argv)
    # word = input('请输入要翻译的单词或句子：')
    word = sys.argv[1]
    king = King(word)
    king.run()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;requestssession-进行状态保持&quot;&gt;requests.session 进行状态保持&lt;/h2&gt;
&lt;p&gt;1、作用：自动处理cookies&lt;/p&gt;

&lt;p&gt;2、场景：连续的多次请求&lt;/p&gt;

&lt;p&gt;3、使用方法：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;session = requests.session                      #实例化session
response = session.get(url, headers=headers)    #调用session方法发送get请求
response = session.post(url, data, headers)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# 知识点：掌握 利用 requests.session 进行状态保持
# 作用：自动处理cookie
# 场景：连续的多次请求
# 使用方法：先利用requests创建session的类，然后借助session类调用get或者post发送请求

# 以 GitHub登陆 为例

import requests
import re

def login():
    # session，创建session对象
    session = requests.session()

    # headers
    session.headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36'
    }

    # url1-获取token
    url1 = 'https://github.com/login'
        # 发送请求获取响应
    res_1 = session.get(url1).content.decode()
        # 正则表达式提取token
    token = re.findall('name=&quot;authenticity_token&quot; value=&quot;(.*?)&quot; /&amp;gt; ', res_1)
          # 'name=&quot;authenticity_token&quot; value=&quot;z/c5WeKPQcc9nQ0wECMnJGKtE3zPtzT85J3QQ/+54ejFtUQW0xkwuA3XA1GA85DTnN4VkXp4i0AYd2iboS4rXw==&quot; /&amp;gt; '
    # print(token)

    # url2-登陆
    url2 = 'https://github.com/session'
        # 构建表单数据
    data = {
        &quot;commit&quot;: &quot;Sign in&quot;,
        &quot;authenticity_token&quot;: token,
        &quot;login&quot;: &quot;ch_cjb@163.com&quot;,
        &quot;password&quot;: &quot;******&quot;,  #密码隐藏
        &quot;webauthn-support&quot;: &quot;supported&quot;,
        &quot;webauthn-iuvpaa-support&quot;: &quot;unsupported&quot;,
        &quot;return_to&quot;: &quot;https://github.com/login&quot;
    }
    # print(data)
        # 发送请求登录
    session.post(url2, data=data)

    # url3-验证
    url3 = 'https://github.com/jinbao1chen'
    response = session.get(url3)
    with open('github_session.html','wb') as f:
        f.write(response.content)

if __name__ == '__main__':
    login()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Mon, 20 Sep 2021 00:00:00 +0000</pubDate>
        <link>https://jinbao1chen.github.io/2021/09/%E7%BD%91%E7%BB%9C%E7%88%AC%E8%99%AB_requests%E6%A8%A1%E5%9D%97/</link>
        <guid isPermaLink="true">https://jinbao1chen.github.io/2021/09/%E7%BD%91%E7%BB%9C%E7%88%AC%E8%99%AB_requests%E6%A8%A1%E5%9D%97/</guid>
        
        <category>爬虫，python</category>
        
        
      </item>
    
      <item>
        <title>C++循环与关系表达式</title>
        <description>&lt;h2 id=&quot;循环与关系表达式&quot;&gt;循环与关系表达式&lt;/h2&gt;
&lt;p&gt;for、while是入口条件循环，do while 是出口条件循环；
输入：cin » ch；忽略空格、换行符和制表符“\t”。cin.get(ch) 和 ch=cin.get()成员函数调用，返回下一个输入字符，包括空格、换行符和制表符“\t”。&lt;/p&gt;

&lt;h2 id=&quot;循环&quot;&gt;循环&lt;/h2&gt;
&lt;h3 id=&quot;for循环&quot;&gt;for循环&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;for(初始化表达式; 测试表达式; 更新表达式) {循环体}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;副作用：判定表达式为“=”时，会带来副作用，即修改被赋值者的值，因为这种操作改变了内存中数据的值。&lt;/p&gt;

&lt;p&gt;顺序点：语句中的分号是一个顺序点，程序处理下一条语句之前，赋值运算符、递增运算符和递减运算符执行的所有修改都必须完成。任何一个完整的表达式（不是其他表达式的子表达式）末尾都是一个顺序点。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;eg1:

while (guessts++ &amp;lt; 10)
	cout &amp;lt;&amp;lt; guessts &amp;lt;&amp;lt; endl;  //测试条件是一个完整的表达式，末尾是一个顺序点，C++确保副作用 guessts 在进入cout之前完成+1.

eg2:

y = (4 + x++) + (6 + x++); //整个表达式末尾分号标示了顺序点，是一个完整表达式，C++只保执行到下条语句前x自增两次，不能保证在每次子表达式计算后将x值增加.

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;while-循环&quot;&gt;while 循环&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;while （判断表达式）
	循环体

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;do-while-循环&quot;&gt;do while 循环&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;do
	循环体
while（循环条件）

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;表达式&quot;&gt;表达式&lt;/h2&gt;

&lt;h3 id=&quot;递增与递减运算符和指针&quot;&gt;递增与递减运算符和指针&lt;/h3&gt;
&lt;p&gt;1、前缀递增、前缀递减（++X、–X）和 解除引用运算符（*X）的优先级相同，以从右到左的方式进行结合；&lt;/p&gt;

&lt;p&gt;2、后缀递增、后缀递减（X++、X–）优先级相同，但比前缀运算符优先级高，以从左到右的方式进行结合。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;eg:

*++pt; //将++应用于pt，然后 * 应用于被递增后的pt.

++*pt; //pt先解除指针引用，将pt指向地址中存储的值加1.

*pt++; //pt指针先递增，然后解除引用.

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;组合运算符&quot;&gt;组合运算符&lt;/h3&gt;
&lt;p&gt;=+、-+、*=、/=、%=&lt;/p&gt;

&lt;h3 id=&quot;复合语句&quot;&gt;复合语句&lt;/h3&gt;
&lt;p&gt;如果在一个语句块中声明一个变量，而外部语句块中也定义了一个这种名称的变量，在声明位置到内部语句块结束的范围内，新变量将隐藏旧变量，然后旧变量再次可见。&lt;/p&gt;

&lt;h3 id=&quot;逗号运算符&quot;&gt;逗号运算符&lt;/h3&gt;
&lt;p&gt;1、合并表达式： 允许将两个表达式放到C++语法只允许放一个表达式的地方。如 ++j,++i&lt;/p&gt;

&lt;p&gt;2、分开变量列表相邻的名称： 如 int x, y;&lt;/p&gt;

&lt;p&gt;3、顺序点： 逗号运算符是一个顺序点。所有运算符中逗号运算符优先级最低。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;eg1:

i = 20, j = 2 * i     //逗号表达式的值是第二部分的值，40

eg2:

x = 17,240;  //等价于 (x=17), 240  后面的值不起作用

eg3:

x = (17,240);  //x的值为240，逗号右侧的表达式值


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;字符串比较&quot;&gt;字符串比较&lt;/h3&gt;
&lt;p&gt;不能用关系运算符来比较字符串，但可以比较字符，字符本质上是整形。&lt;/p&gt;

&lt;h3 id=&quot;比较string类字符串&quot;&gt;比较string类字符串&lt;/h3&gt;
&lt;p&gt;可以将关系运算符用于string类&lt;/p&gt;
</description>
        <pubDate>Tue, 06 Jul 2021 00:00:00 +0000</pubDate>
        <link>https://jinbao1chen.github.io/2021/07/C++%E5%BE%AA%E7%8E%AF%E5%92%8C%E5%85%B3%E7%B3%BB%E8%A1%A8%E8%BE%BE%E5%BC%8F/</link>
        <guid isPermaLink="true">https://jinbao1chen.github.io/2021/07/C++%E5%BE%AA%E7%8E%AF%E5%92%8C%E5%85%B3%E7%B3%BB%E8%A1%A8%E8%BE%BE%E5%BC%8F/</guid>
        
        <category>C++</category>
        
        
      </item>
    
      <item>
        <title>C++数据类型</title>
        <description>&lt;p&gt;　　C++一些基本复合数据类型，字符串、string类型、结构、枚举、共用体、指针&lt;/p&gt;

&lt;h2 id=&quot;背景&quot;&gt;背景&lt;/h2&gt;

&lt;p&gt;　C++复合类型&lt;/p&gt;

&lt;h2 id=&quot;复合类型&quot;&gt;复合类型&lt;/h2&gt;

&lt;h3 id=&quot;字符串&quot;&gt;字符串&lt;/h3&gt;
&lt;p&gt;面向行的输入： getline()读取整行，通过回车键输入的换行符结束。&lt;/p&gt;

&lt;p&gt;$ cin.getline(str,num); 将一串字符读入到一个包含num个元素的数组中。&lt;/p&gt;

&lt;p&gt;面向行的输入： get() 与getline()相似，但读取换行符，需再次调用来换行。&lt;/p&gt;

&lt;p&gt;cin.get(str,num); //读取第一行&lt;/p&gt;

&lt;p&gt;cin.get();        //使用不带参数调用可读取下一个字符，即使是换行符&lt;/p&gt;

&lt;p&gt;cin.get(str1,num); //读取第二行&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;string&amp;gt;

int main()
{
	using namespace std;
	const int Size = 20;
	//char name1[Size];
	//char name2[Size];
	string name1,name2;
	cout &amp;lt;&amp;lt; &quot;Enter your first name: &quot;;
	//cin.getline(name1,Size);  不能与string类型的变量搭配。
	cin &amp;gt;&amp;gt; name1;
	cout &amp;lt;&amp;lt; &quot;Enter your last name: &quot;;
	//cin.get(name2,Size);
	//cin.get();
	cin &amp;gt;&amp;gt; name2;
	cout &amp;lt;&amp;lt; &quot;Here's information in a single string: &quot; &amp;lt;&amp;lt; name1 &amp;lt;&amp;lt; &quot;, &quot; &amp;lt;&amp;lt; name2;
	cout &amp;lt;&amp;lt; endl;
	return 0;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;//使用char数组和头文件cstring中函数，拼接名字
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;cstring&amp;gt;

int main()
{
	using namespace std;
	const int Size = 15;
	char name1[Size];
	char name2[Size];
	cout &amp;lt;&amp;lt; &quot;Enetr your first name: &quot;;
	cin &amp;gt;&amp;gt; name1;
	cout &amp;lt;&amp;lt; &quot;Enter your last name: &quot;;
	cin &amp;gt;&amp;gt; name2;
	cout &amp;lt;&amp;lt; &quot;Here's the information in a string string: &quot; &amp;lt;&amp;lt; name1 &amp;lt;&amp;lt; &quot;, &quot; &amp;lt;&amp;lt; name2;
	cout &amp;lt;&amp;lt; endl;
	return 0;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;string类型&quot;&gt;string类型&lt;/h3&gt;

&lt;p&gt;string类型的变量，std::string str;&lt;/p&gt;

&lt;p&gt;1、声明创建时长度为0，程序执行时自动调整str字符串的长度；&lt;/p&gt;

&lt;p&gt;2、与普通字符串数组的区别是，string类对象可以赋值给另一个string类对象；&lt;/p&gt;

&lt;p&gt;3、字符串合并，可直接使用运算符‘+ =’.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#include&amp;lt;iostream&amp;gt;
#include&amp;lt;string&amp;gt;

int main()
{
	using namespace std;
	string name, dessert;

	cout &amp;lt;&amp;lt; &quot;Enter your name:\n&quot;;
	cin &amp;gt;&amp;gt; name;
	cout &amp;lt;&amp;lt; &quot;Enter your favorite dessert: \n&quot;;
	cin &amp;gt;&amp;gt; dessert;

	cout &amp;lt;&amp;lt; &quot;I have some delicious &quot; &amp;lt;&amp;lt; dessert;
	cout &amp;lt;&amp;lt; &quot;for you, &quot; &amp;lt;&amp;lt; name &amp;lt;&amp;lt; endl;


	return 0;
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;枚举&quot;&gt;枚举&lt;/h3&gt;

&lt;p&gt;枚举enum：一种创建符号常量的方式，可以代替const&lt;/p&gt;

&lt;p&gt;1、默认情况下，将整数赋值给枚举量，第一个为0，第二个为1，也可以显式指定整数值给枚举量，下一个枚举量默认加1&lt;/p&gt;

&lt;p&gt;2、在不强制转换类型时，只能将定义枚举时使用的枚举量赋值给这种枚举型的变量&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;//枚举型变量： spectrum  枚举值：
enum spectrum = 
{
	red, orange, yellow, green, blue, violet, indigo, ultraviolet
};
//声明枚举类型的变量
spectrum band;

//枚举量赋值
band = bule; //只能将已存在的枚举量赋值给枚举型变量band
int color = blue; //枚举量是整型，可以被提升为int型，但是int类型不能自动转换为枚举类型，bulue = 3非法

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;共用体union&quot;&gt;共用体union&lt;/h3&gt;

&lt;p&gt;共用体union： 一种数据格式，能够储存不同的数据类型，但同时只能存储其中的一种类型。且必须有足够的空间来存储最大的成员，共用体的最大长度为其最大成员的长度&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;union onein4all
{
	int int_val;
	long long_val;
	double double_val;
	char char_val[10];
}

//使用时只能同时使用其中一种类型
onein4all pail;
pail.int_val = 15; //存储一个整型数据

pail.double = 1.25; //存储一个小数

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;结构体&quot;&gt;结构体　&lt;/h3&gt;
&lt;p&gt;1、练习结构体的声明与初始化&lt;/p&gt;

&lt;p&gt;2、声明结构变量： 结构体数组&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;

struct CandyBar
{
	char 	brand[20];
	double  weight;
	int 	Calori;
};

int main(int argc, char const *argv[])
{
	using namespace std;

	//结构体初始化
	CandyBar snack = {&quot;Mocha Munch&quot;,2.3,350};

	cout &amp;lt;&amp;lt; &quot;Expand your guest list: &quot; &amp;lt;&amp;lt; snack.brand &amp;lt;&amp;lt; &quot;,&quot; &amp;lt;&amp;lt; snack.weight &amp;lt;&amp;lt; &quot;, &quot; &amp;lt;&amp;lt; snack.Calori;
	cout &amp;lt;&amp;lt; endl;

	//声明结构变量
	CandyBar snacks[2] = 
	{
		{&quot;KFC&quot;,3.1,520},
		{&quot;MacDonald&quot;,4.2,600}
	};
	cout &amp;lt;&amp;lt; &quot;The first snack list: &quot; &amp;lt;&amp;lt; snacks[0].brand &amp;lt;&amp;lt; &quot;, &quot; &amp;lt;&amp;lt; snacks[0].weight &amp;lt;&amp;lt; &quot;, &quot; &amp;lt;&amp;lt; snacks[0].Calori;
	cout &amp;lt;&amp;lt; endl;
	cout &amp;lt;&amp;lt; &quot;The second snack list: &quot; &amp;lt;&amp;lt; snacks[1].brand &amp;lt;&amp;lt; &quot;, &quot; &amp;lt;&amp;lt; snacks[1].weight &amp;lt;&amp;lt; &quot;, &quot; &amp;lt;&amp;lt; snacks[1].Calori;
	cout &amp;lt;&amp;lt; endl; 
	
	return 0;
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;指针&quot;&gt;指针&lt;/h3&gt;

&lt;p&gt;3、使用new为结构分配内存。C++使用关键字new允许程序在运行时请求正确数量的内存，以及使用指针来跟踪新分配的内存的位置&lt;/p&gt;

&lt;p&gt;4、指针： int* 是一种复合类型，是指向int的指针&lt;/p&gt;

&lt;p&gt;5、int * pt = new int; //程序运行时为一个int值分配未命名的内存，并使用指针pt来访问这个值&lt;/p&gt;

&lt;p&gt;6、typeName * pointer = new typeName; //为一个数据对象（结构、基本类型）获得并指定分配的通用格式&lt;/p&gt;

&lt;p&gt;7、new从堆或自由存储区的内存区域分配内存，常规变量声明的值存储在栈的内存区域&lt;/p&gt;

&lt;p&gt;8、delete： 释放由new分配的内存，一定要配对使用
  / int * pt = new int; …; delete pt; delete要加上指向内存块的地址，删除pt指向的内存，但不会删除指针pt本身&lt;/p&gt;

&lt;p&gt;9、new的用武之地在于对大型数据（数组、字符串和结构），如使用new创建动态数组：
  / int * psome = new int [10]; …; delete [] psome; 方括号告诉程序应释放整个数组，而不仅仅是指针指向的元素，注意：psome是指向第一个int(数组第一个元素)的指针&lt;/p&gt;

&lt;p&gt;10、通过指针psome使用动态数组： 把指针当做数组名使用，可直接使用psome[index]来操作数组元素，例如，对于第一个元素可以使用psome[0]，而不是 *psome&lt;/p&gt;

&lt;p&gt;11、指针与数组名的区别： 不能修改数组名的值，但指针是变量，可以修改它的值，如 psome = psome + 1; 表示psome现在指向的数组位置是当前元素的下一个元素&lt;/p&gt;

&lt;p&gt;12、数组： short tell[10]; &amp;amp;tell 对数组名运用取地址运算符时，得到的是整个数组的地址。tell是数组第一个元素的地址，等价于&amp;amp;tell[0]. 虽然两者地址相同，但是
  / 从概念上&amp;amp;tell是一个20字节（假设short是2个字节）内存块的地址，而tell即&amp;amp;tell[0]是一个2字节内存块的地址&lt;/p&gt;

&lt;h3 id=&quot;new创建动态结构&quot;&gt;new创建动态结构&lt;/h3&gt;
&lt;p&gt;1、创建： inflatable * ps = new inflatable; //把一块存储inflatable结构的一块可用的内存地址赋给ps&lt;/p&gt;

&lt;p&gt;2、使用： &lt;em&gt;ps表示结构本身，（&lt;/em&gt;ps）.price 是该结构的price成员&lt;/p&gt;

&lt;p&gt;3、释放： delete ps;&lt;/p&gt;

&lt;h3 id=&quot;变量类型&quot;&gt;变量类型&lt;/h3&gt;
&lt;p&gt;自动变量： 在函数内部定义的常规变量使用自动存储空间，函数结束自动消亡。存储在栈中，执行代码块时变量将依次加入到栈中，离开时按相反顺序释放，称为后进先出（LIFO ），因此程序执行过程中栈将不断地增大和缩小。&lt;/p&gt;

&lt;p&gt;静态变量： 函数外定义 或 声明变量使用关键字static。&lt;/p&gt;

&lt;p&gt;动态变量： new/delete，管理一个内存池，称为自由存储空间或堆。允许跨函数释放，但内存管理复杂。在栈中，自动添加和删除机制使得占用内存总是连续的，但new和delete相互影响可能导致占用的自由存储区域不连续，跟踪新分配额内存的位置困难。&lt;/p&gt;

&lt;h3 id=&quot;数组替代品模板类vertor和array&quot;&gt;数组替代品–模板类vertor和array&lt;/h3&gt;

&lt;p&gt;1、模板类vector: 类似于string类，一种动态数组，可以在程序运行时设置vector对象的长度，可以在结尾附加新数据或在中间插入新数据。&lt;/p&gt;

&lt;p&gt;说明：头文件 #include &lt;vector&gt; , vector包含在std名称空间中std::vector&lt;/vector&gt;&lt;/p&gt;

&lt;p&gt;使用：模板使用不同语法来指出它存储的数据类型和元素个数&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;vector&amp;lt;typeName&amp;gt; vt(n_elem)
//声明创建一个名为vt的vector对象，它可存储n_elem个类型为typeName的元素。如 vector&amp;lt;int&amp;gt; vt(1), vt的初始长度可以为零，使用vectord的各种方法调整。

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;特点： 比数组功能强大，效率稍低。&lt;/p&gt;

&lt;p&gt;2、模板类array： 与数组一样，长度固定，也使用栈（静态内存分配），位于名称空间std中。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;array&amp;lt;typeName, n_elem&amp;gt; arr;
//声明创建一个名为arr的array对象，它包含n_elem个类型为typeName的元素，如array&amp;lt;int,4&amp;gt; arr;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;3、模板类的一些成员函数，如vt.at()、vt.begin()、vt.end()等，可防止越界。&lt;/p&gt;

&lt;p&gt;无论数组、vector对象，还是array对象，都可以使用数组表示法访问各个元素。&lt;/p&gt;

&lt;p&gt;array对象和数组存储在相同的内存区域（栈）中，而vertor存储在堆。&lt;/p&gt;

&lt;p&gt;array对象可以赋值给另一个array对象，如array&amp;lt;int,4&amp;gt; a1，a2; a1 = a2； 而数组必须逐元素赋值。&lt;/p&gt;
</description>
        <pubDate>Sun, 20 Jun 2021 00:00:00 +0000</pubDate>
        <link>https://jinbao1chen.github.io/2021/06/C++%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B/</link>
        <guid isPermaLink="true">https://jinbao1chen.github.io/2021/06/C++%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B/</guid>
        
        <category>C++</category>
        
        
      </item>
    
  </channel>
</rss>
