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

建设企业网站的好处上传wordpress到空间

建设企业网站的好处,上传wordpress到空间,网站开发文章,从化网站开发C实现MySQL数据库连接池 涉及技术 MySQL数据库编程、单例模式、STL容器、C11多线程#xff08;线程互斥、线程互斥、线程同步通信和unique_lock#xff09;、智能指针shared_ptr、lambda表达式、生产者-消费者线程模型。 项目背景 为了提升MySQL数据库#xff08;基于C/…C实现MySQL数据库连接池 涉及技术 MySQL数据库编程、单例模式、STL容器、C11多线程线程互斥、线程互斥、线程同步通信和unique_lock、智能指针shared_ptr、lambda表达式、生产者-消费者线程模型。 项目背景 为了提升MySQL数据库基于C/S设计客户端-服务器的访问瓶颈除了在服务器端增加缓冲服务器缓存常用的数据之外例如radis、其实也就是建立一个常访问的key-value对便于快速索引还可以增加连接池。来提高MySQL Server的访问效率在高并发环境下大量的TCP三次握手、MySQl Server连接验证、MySQL Server关闭连接回收资源和TCP四次挥手 所耗费的性能时间也是很明显的增加连接池就是为了减少这一部分性能损耗直接从数据池中获取可用连接就不用重新建立连接。客户端和数据库服务器端的通信一般分为建立TCP连接、MySQL连接的验证和指令通信TCP四次挥手更多TCP连接和断开可以查看一文彻底搞懂 TCP三次握手、四次挥手过程及原理。 目前市场主流的连接池有druidc3p0和apache dbcp连接池他们对于短时间内大量的数据库增删改查操作性能的提升是很明显的但是它们都是基于Java实现的。 连接池的功能 连接池一般包含了数据库连接所使用的ip地址、port端口、用户名和密码以及其他的性能参数例如初始连接量、最大连接量、最大空闲时间、连接超时时间该项目主要是基于C实现的连接池主要实现以上几个所有连接池都支持的通用功能。 初始连接量(initSize)表示连接池事先会和MySQL Server创建initSize个数的connection连接当应用发起MySQL访问时不用再创建和MySQL Server新的连接直接从连接池中获取一个可用的连接就可以使用完成后并不去释放connection而是把当前connection再归还到连接池当中。 最大连接量(maxSize)当并发访问MySQL Server的请求增多时初始连接量已经不够使用了此时会根据新的请求数量去创建更多的连接给应用去使用但是新创建的连接数量上限是maxSize不能无限制的创建连接因为每一个连接都会占用一个socket资源一般连接池和服务器程序是部署在一台主机上的如果连接池占用过多的socket资源那么服务器就不能接收太多的客户端请求了。当这些连接使用完成后再次归还到连接池当中来维护。 最大空闲时间(maxIdleTime)当访问MySQL的并发请求多了以后连接池里面的连接数量会动态增加上限是maxSize个当这些连接用完再次归还到连接池当中。如果在指定的maxIdleTime里面这些新增加的连接都没有被再次使用过那么新增加的这些连接资源就要被回收掉只需要保持初始连接量initSize个连接就可以了。 连接超时时间(connectionTimeOut)当MySQL的并发请求量过大连接池中的连接数量已经到达maxSize了而此时没有空闲的连接可供使用那么此时应用从连接池获取连接无法成功它通过阻塞的方式获取连接的时间如果超过connectionTimeout时间那么获取连接失败无法访问数据库。 MySQL Server参数介绍 功能实现设计 ConnectionPool.cpp和ConnectionPool.h连接池代码实现 Connection.cpp和Connection.h数据库操作代码、增删改查代码实现 连接池主要包含了以下功能点 1.连接池只需要一个实例所以ConnectionPool以单例模式进行设计 2.从ConnectionPool中可以获取和MySQL的连接Connection 3.空闲连接Connection全部维护在一个线程安全的Connection队列中使用线程互斥锁保证队列的线程安全 4.如果Connection队列为空还需要再获取连接此时需要动态创建连接上限数量是maxSize 5.队列中空闲连接时间超过maxIdleTime的就要被释放掉只保留初始的initSize个连接就可以了这个功能点肯定需要放在独立的线程中去做 6.如果Connection队列为空而此时连接的数量已达上限maxSize那么等待connectionTimeout时间如果还获取不到空闲的连接那么获取连接失败此处从Connection队列获取空闲连接可以使用带超时时间的mutex互斥锁来实现连接超时时间 7.用户获取的连接用shared_ptr智能指针来管理用lambda表达式定制连接释放的功能不真正释放连接而是把连接归还到连接池中 8.连接的生产和连接的消费采用生产者-消费者线程模型来设计使用了线程间的同步通信机制条件变量和互斥锁 实现代码参考 connection.h #pragma once #include mysql.h #include string #includectime using namespace std;// 数据库操作类 class Connection { public:// 初始化数据库连接Connection();// 释放数据库连接资源~Connection();// 连接数据库bool connect(string ip, unsigned short port, string user, string password,string dbname);// 更新操作 insert、delete、updatebool update(string sql);// 查询操作 selectMYSQL_RES* query(string sql);//刷新一下连接的起始的空闲时间void refreshAliveTime();//返回连接的存活时间clock_t getAliveTime(); private:MYSQL* _conn; // 表示和MySQL Server的一条连接clock_t _alivetime;//记录进入空闲状态后的起始时间 };connection.cpp #includeconnection.h #includepublic.h// 初始化数据库连接 Connection::Connection() {_conn mysql_init(nullptr); } // 释放数据库连接资源 Connection::~Connection() {if (_conn ! nullptr)mysql_close(_conn); } // 连接数据库 bool Connection::connect(string ip, unsigned short port, string user, string password,string dbname) {MYSQL* p mysql_real_connect(_conn, ip.c_str(), user.c_str(),password.c_str(), dbname.c_str(), port, nullptr, 0);return p ! nullptr; } // 更新操作 insert、delete、update bool Connection::update(string sql) {if (mysql_query(_conn, sql.c_str())){LOG(更新失败: sql);return false;}return true; } // 查询操作 select MYSQL_RES* Connection::query(string sql) {if (mysql_query(_conn, sql.c_str())){LOG(查询失败: sql);return nullptr;}return mysql_use_result(_conn); } //刷新一下连接的起始的空闲时间 void Connection::refreshAliveTime() {_alivetime clock_t(); }//返回连接的存活时间 clock_t Connection::getAliveTime() {return clock() - _alivetime; }commConnectionPool.h #pragma once #includestring #includequeue #includemutex #includeatomic #includethread #includememory #includefunctional #includecondition_variable #includeconnection.husing namespace std;class ConnectionPool { public://获取连接池对象实例静态成员方法不依赖于对象调用static ConnectionPool* getConnectionPool();//从线程池中获取线程shared_ptrConnection getConnection(); private:// 单例构造函数私有化ConnectionPool();//加载配置文件bool loadConfigFile();//用来线程来产生连接void produceConnectionTask();//用来扫描连接的进程函数防止很线程池中线程数量大于initSize而不归还资源void scannerConnectionTask();string _ip; //mysql的ip地址unsigned short _port; //mysql的端口号string _username; //mysql的连接用户名string _password; //mysql连接用户的密码string _dbname;int _initSize; //初始化连接池的数量int _maxSize; //最大化连接池的数量int _maxIdleTime; //连接池最大空闲时间int _connectionTimeout;//连接池最大获取时间queueConnection* _connectionQue; //连接池存储数据库连接队列必须是多线程安全的mutex _queueMutex;//维护连接池队列线程安全的互斥锁atomic_int _connectionCnt;//记录所创建的connection数量condition_variable cv;//设置条件变量用于连接生产线程和连接消费线程的实现 };commConnectionPool.cpp #includecommConnectionPool.h #includepublic.h//线程安全的懒汉单例模式接口 ConnectionPool* ConnectionPool::getConnectionPool() {//静态局部变量由编译器自动lock和unlockstatic ConnectionPool pool;return pool; }//从线程池中获取线程 shared_ptrConnection ConnectionPool::getConnection() {unique_lockmutex lock(_queueMutex);while (_connectionQue.empty()) {if (cv_status::timeout cv.wait_for(lock, chrono::milliseconds(_connectionTimeout))){if (_connectionQue.empty()) {LOG(获取空闲连接超时获取失败!);return nullptr;}}}/*shared_ptr智能指针析构时会把connection资源直接给delete掉相当于调用了Connection的析构函数connect就会被关闭掉了这里需要自定义shared_ptr的释放资源方式把connection归还到队列中*/shared_ptrConnection sp(_connectionQue.front(),[](Connection* pcon) {//这里是在服务器应用线程中调用的所以一定要考虑线程安全unique_lockmutex lock(_queueMutex);//智能指针析构的时候会将指针重新输入到队列中_connectionQue.push(pcon);pcon-refreshAliveTime();});_connectionQue.pop();cv.notify_all();//消费完连接之后通知生产者线程检查一下如果生产队列为空后就通知线程赶紧生产return sp; }ConnectionPool::ConnectionPool() {if (!loadConfigFile()) {return;}for (int i 0; i _initSize; i) {Connection* p new Connection();p-connect(_ip, _port, _username, _password, _dbname);p-refreshAliveTime();_connectionQue.push(p);_connectionCnt;}//启动一个新的线程作为一个连接的生产者thread produce(std::bind( ConnectionPool::produceConnectionTask, this));//分离线程分离线程主线程结束后该线程自动结束produce.detach();//启动一个定时线程扫描超过maxIdleTime时间的空闲线程thread scanner(std::bind(ConnectionPool::scannerConnectionTask, this));scanner.detach(); }//用来扫描连接的进程函数防止很线程池中线程数量大于initSize而不归还资源 void ConnectionPool::scannerConnectionTask() {while (true) {//通过sleep模拟定时效果this_thread::sleep_for(chrono::seconds(_maxIdleTime));//扫秒整个队列释放多余的连接//队列要用互斥锁防止多线程访问unique_lockmutex lock(_queueMutex);while (_connectionCnt _initSize){Connection* p _connectionQue.front();//如果队列头都没有超时的话那么后面的connection肯定不会超时//每次回收返回队列都是插入在队尾的if (p-getAliveTime() _maxIdleTime){_connectionQue.pop();_connectionCnt--;delete p;}else {break;}}} }//用来线程来产生连接 void ConnectionPool::produceConnectionTask() {while (true) {//所有的线程在创建时都被_queueMutex锁住了共用一把锁函数作用域结束后默认解锁//unique_lock无默认参数时会自动加锁unique_lockmutex lock(_queueMutex);while (!_connectionQue.empty()) {//condition_variable cv 必须和unique_lock一起使用cv.wait(lock);//队列不为空此处生产者线程进入等待状态}if (_connectionCnt _maxSize) {Connection* p new Connection();p-connect(_ip, _port, _username, _password, _dbname);p-refreshAliveTime();_connectionQue.push(p);_connectionCnt;}cv.notify_all();//通知消费者线程可以进行连接了} }bool ConnectionPool::loadConfigFile() {//读取配置文件FILE* pf fopen(./mysql.ini, r);if (pf nullptr) {LOG(mysql.ini file is not exist!);return false;}//feof()函数判断文件字节流是否到了末尾while (!feof(pf)) {char line[1024] { 0 };//fgets获取文件一行并指定行的最大值包含最后的空字符//如果成功该函数返回相同的 str 参数。//如果到达文件末尾或者没有读取到任何字符str 的内容保持不变并返回一个空指针。//如果发生错误返回一个空指针。fgets(line, 1024, pf);string str line;int idxstr.find(, 0);if (idx -1) {//无效的配置continue;}int endx str.find(\n, idx);string key str.substr(0, idx);string value str.substr(idx 1, endx - idx - 1);if (key ip) {_ip value;}else if (key port) {_port atoi(value.c_str());}else if (key username) {_username value;}else if (key password) {_password value;}else if (key dbname) {_dbname value;}else if (key initSize) {_initSize atoi(value.c_str());}else if (key maxSize) {_maxSize atoi(value.c_str());}else if (key maxIdleTime) {_maxIdleTime atoi(value.c_str());}else if (key connectionTimeout) {_connectionTimeout atoi(value.c_str());}}return true; } public.h #pragma once #includeiostream#define LOG(str) std::cout__FILE__ : __LINE__ : __TIMESTAMP__ : strendl;main.cpp #includeiostream #includestring #includectime #includethread #includeconnection.h #includecommConnectionPool.husing namespace std;int main(int argc, char argv[]) {clock_t begin clock();int number 5000;bool is_use_connection_pool true;/*if (!is_use_connection_pool){for (int i 0; i number; i){Connection conn;conn.connect(127.0.0.1, 3306, root, xiehou, chat);char sql[1024] { 0 };// 项目属性 - C/C - 预处理器 - 预处理定义上加上_CRT_SECURE_NO_DEPRECATE和_SCL_SECURE_NO_DEPRECATE使用分号隔开sprintf(sql, insert into user(name,age,sex) values(%s,%d,%s), zhangsan, 20, male);conn.update(sql);}}else {//获取静态唯一的连接池也是静态变量和静态方法的好处ConnectionPool* pool ConnectionPool::getConnectionPool();for (int i 0; i number; i){shared_ptrConnection sp pool-getConnection();char sql[1024] { 0 };// 项目属性 - C/C - 预处理器 - 预处理定义上加上_CRT_SECURE_NO_DEPRECATE和_SCL_SECURE_NO_DEPRECATE使用分号隔开sprintf(sql, insert into user(name,age,sex) values(%s,%d,%s), zhangsan, 20, male);sp-update(sql);}}*/Connection conn;conn.connect(127.0.0.1, 3306, root, xiehou, chat);//多线程-未使用连接池thread t1([]() {for (int i 0; i 250; i){Connection conn;conn.connect(127.0.0.1, 3306, root, xiehou, chat);char sql[1024] { 0 };// 项目属性 - C/C - 预处理器 - 预处理定义上加上_CRT_SECURE_NO_DEPRECATE和_SCL_SECURE_NO_DEPRECATE使用分号隔开sprintf(sql, insert into user(name,age,sex) values(%s,%d,%s), zhangsan, 20, male);conn.update(sql);}});thread t2([]() {for (int i 0; i 250; i){Connection conn;conn.connect(127.0.0.1, 3306, root, xiehou, chat);char sql[1024] { 0 };// 项目属性 - C/C - 预处理器 - 预处理定义上加上_CRT_SECURE_NO_DEPRECATE和_SCL_SECURE_NO_DEPRECATE使用分号隔开sprintf(sql, insert into user(name,age,sex) values(%s,%d,%s), zhangsan, 20, male);conn.update(sql);}});thread t3([]() {for (int i 0; i 250; i){Connection conn;conn.connect(127.0.0.1, 3306, root, xiehou, chat);char sql[1024] { 0 };// 项目属性 - C/C - 预处理器 - 预处理定义上加上_CRT_SECURE_NO_DEPRECATE和_SCL_SECURE_NO_DEPRECATE使用分号隔开sprintf(sql, insert into user(name,age,sex) values(%s,%d,%s), zhangsan, 20, male);conn.update(sql);}});thread t4([]() {for (int i 0; i 250; i){Connection conn;conn.connect(127.0.0.1, 3306, root, xiehou, chat);char sql[1024] { 0 };// 项目属性 - C/C - 预处理器 - 预处理定义上加上_CRT_SECURE_NO_DEPRECATE和_SCL_SECURE_NO_DEPRECATE使用分号隔开sprintf(sql, insert into user(name,age,sex) values(%s,%d,%s), zhangsan, 20, male);conn.update(sql);}});//多线程-线程池/*thread t1([]() {ConnectionPool* pool ConnectionPool::getConnectionPool();for (int i 0; i 1250; i){shared_ptrConnection sp pool-getConnection();char sql[1024] { 0 };// 项目属性 - C/C - 预处理器 - 预处理定义上加上_CRT_SECURE_NO_DEPRECATE和_SCL_SECURE_NO_DEPRECATE使用分号隔开sprintf(sql, insert into user(name,age,sex) values(%s,%d,%s), zhangsan, 20, male);sp-update(sql);}});thread t2([]() {ConnectionPool* pool ConnectionPool::getConnectionPool();for (int i 0; i 1250; i){shared_ptrConnection sp pool-getConnection();char sql[1024] { 0 };// 项目属性 - C/C - 预处理器 - 预处理定义上加上_CRT_SECURE_NO_DEPRECATE和_SCL_SECURE_NO_DEPRECATE使用分号隔开sprintf(sql, insert into user(name,age,sex) values(%s,%d,%s), zhangsan, 20, male);sp-update(sql);}});thread t3([]() {ConnectionPool* pool ConnectionPool::getConnectionPool();for (int i 0; i 1250; i){shared_ptrConnection sp pool-getConnection();char sql[1024] { 0 };// 项目属性 - C/C - 预处理器 - 预处理定义上加上_CRT_SECURE_NO_DEPRECATE和_SCL_SECURE_NO_DEPRECATE使用分号隔开sprintf(sql, insert into user(name,age,sex) values(%s,%d,%s), zhangsan, 20, male);sp-update(sql);}});thread t4([]() {ConnectionPool* pool ConnectionPool::getConnectionPool();for (int i 0; i 1250; i){shared_ptrConnection sp pool-getConnection();char sql[1024] { 0 };// 项目属性 - C/C - 预处理器 - 预处理定义上加上_CRT_SECURE_NO_DEPRECATE和_SCL_SECURE_NO_DEPRECATE使用分号隔开sprintf(sql, insert into user(name,age,sex) values(%s,%d,%s), zhangsan, 20, male);sp-update(sql);}});*///join表示要等子线程结束后后面的主线程才能继续执行也就是end计时要等t1~t4结束后才能执行detach则不用等待t1.join();t2.join();t3.join();t4.join();clock_t end clock();std::cout (end - begin) ms endl;return 0; }mysql.ini # 用于存储mysql的基本连接信息 ip127.0.0.1 port3306 usernameroot passwordxiehou dbnamechat initSize10 maxSize1024 # 单位是秒 maxIdleTime60 # 单位是毫秒 connectionTimeout100压力测试 数据量未使用连接池消耗时间ms使用连接池消耗的时间ms1000单线程10548 三线程3472单线程4577 三线程28585000单线程53145 三线程17485单线程22877 三线程14865 C多进程/多线程 更多详细资料可以查看C多线程详解全网最全。 主要涉及头文件thread、mutex、atomic、condition_variable、future。 MySQL数据库常用命令 MySQL数据库程序需要以;结尾类似于C/C程序一样。并且MySQL程序对大小写不敏感也就是不太区分大小写。 数据库相关 创建数据库命令 create database name; //管理员用户 mysqladmin -u root -p create name //普通用户需要使用管理员权限如果数据库存在则会创建失败得到类似以下信息ERROR 1007 (HY000): Cant create database name; database exists。 推荐的创建命令是CREATE DATABASE IF NOT EXISTS name DEFAULT CHARSET utf8 COLLATE utf8_general_ci; 删除数据库命令 drop database name删除数据库的时候将会有提示信息确定是否删除。 选择数据库 use name显示数据库所有表格 show tables;数据库表格相关 数据类型 MySQL 支持多种类型大致可以分为三类数值、日期/时间和字符串(字符)类型。 数值类型 MySQL 支持所有标准 SQL 数值数据类型。 这些类型包括严格数值数据类型(INTEGER、SMALLINT、DECIMAL 和 NUMERIC)以及近似数值数据类型(FLOAT、REAL 和 DOUBLE PRECISION)。 关键字INT是INTEGER的同义词关键字DEC是DECIMAL的同义词。 BIT数据类型保存位字段值并且支持 MyISAM、MEMORY、InnoDB 和 BDB表。 作为 SQL 标准的扩展MySQL 也支持整数类型 TINYINT、MEDIUMINT 和 BIGINT。 日期和时间类型 表示时间值的日期和时间类型为DATETIME、DATE、TIMESTAMP、TIME和YEAR。 每个时间类型有一个有效值范围和一个零值当指定不合法的MySQL不能表示的值时使用零值。 字符串类型 字符串类型指CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM和SET。 数据表格常用命令 创建数据表格 CREATE TABLE table_name (column_name column_type);以下例子中我们将在数据库中创建数据表runoob_tbl注意的是表名和列名都不需要引号括起来 CREATE TABLE IF NOT EXISTS runoob_tbl(runoob_id INT UNSIGNED AUTO_INCREMENT,runoob_title VARCHAR(100) NOT NULL,runoob_author VARCHAR(40) NOT NULL,submission_date DATE,sex ENUM(男,女) DEFAULT NULL,PRIMARY KEY ( runoob_id ) )ENGINEInnoDB DEFAULT CHARSETutf8;实例解析 如果你不想字段为 NULL 可以设置字段的属性为 NOT NULL 在操作数据库时如果输入该字段的数据为NULL 就会报错。 AUTO_INCREMENT定义列为自增的属性一般用于主键数值会自动加1。 PRIMARY KEY关键字用于定义列为主键。 您可以使用多列来定义主键列间以逗号分隔。 ENGINE 设置存储引擎CHARSET 设置编码。 mysql create table user(- id INT UNSIGNED AUTO_INCREMENT,- name VARCHAR(50) NOT NULL,- age INT NOT NULL,- sex ENUM(male,female) NOT NULL,- PRIMARY KEY (id)- )ENGINEInnoDB DEFAULT CHARSETutf8;删除数据表格 DROP TABLE table_name ;插入数据 INSERT INTO table_name ( field1, field2,...fieldN )VALUES( value1, value2,...valueN );如果数据是字符型必须使用单引号或者双引号如“value”。 查询数据 SELECT column_name,column_name FROM table_name [WHERE Clause] [LIMIT N][ OFFSET M]查询语句中可以使用一个或者多个表表之间使用逗号(,)分割并使用WHERE语句来设定查询条件。SELECT命令可以读取一条或者多条记录。可以使用星号*来代替其他字段SELECT语句会返回表的所有字段数据可以使用 WHERE语句来包含任何条件。可以使用 LIMIT属性来设定返回的记录数。可以通过OFFSET指定SELECT语句开始查询的数据偏移量。默认情况下偏移量为0。 where语句 以下是 SQL SELECT 语句使用 WHERE 子句从数据表中读取数据的通用语法 SELECT field1, field2,...fieldN FROM table_name1, table_name2... [WHERE condition1 [AND [OR]] condition2.....查询语句中你可以使用一个或者多个表表之间使用逗号, 分割并使用WHERE语句来设定查询条件。可以在 WHERE子句中指定任何条件。可以使用 AND 或者 OR 指定一个或多个条件。WHERE 子句也可以运用于 SQL 的 DELETE 或者 UPDATE 命令。WHERE 子句类似于程序语言中的 if 条件根据 MySQL 表中的字段值来读取指定的数据。 查看表格状态 desc table_name;样例如下 mysql desc user; ------------------------------------------------------------------ | Field | Type | Null | Key | Default | Extra | ------------------------------------------------------------------ | id | int unsigned | NO | PRI | NULL | auto_increment | | name | varchar(50) | NO | | NULL | | | age | int | NO | | NULL | | | sex | enum(male,female) | NO | | NULL | | ------------------------------------------------------------------ 4 rows in set (0.01 sec)常见问题 error C4996: ‘sprintf’: This function or variable may be unsafe. Consider using sprintf_s instead. 在VS中设置项目属性 - C/C - 预处理器 - 预处理定义上加上_CRT_SECURE_NO_DEPRECATE和_SCL_SECURE_NO_DEPRECATE使用分号隔开。
http://www.tj-hxxt.cn/news/131290.html

相关文章:

  • 网站设计怎么做链接沈阳康平志诚建设集团网站
  • 深圳市研发网站建设哪家好nas怎么做自己的网站
  • 安徽阜阳网站建设公司小企业做网站
  • 有哪些做数据分析的网站潍坊哪里能找到做网站的
  • 华为官方网站手机商城首页wordpress返回顶部插件
  • 江西哪里可以做企业网站番禺做网站设计
  • 宁波网站建设价格费用专门做金融的招聘网站
  • 在家做兼职哪个网站免费咨询话术
  • php做的网站如何发布wordpress怎么排版
  • 专业网站制作地址网页怎么建设
  • 现在什么网站做推广比较好企业门户网站建设管理制度
  • 哪些网站会盗取中国电子商务官网
  • 建设flash网站做网站推广员图片处理问题
  • 本机做网站校内二级网站建设整改方案
  • 和一个网站做接口邯郸网站设计多少钱
  • 网站建设收费标准不一推广标题怎么写
  • 网站建设的商品编码活动手机网站开发
  • 微网站公司哪个是网络营销导向网站建设的基础
  • 昆山做企业网站中国建筑网官网电工证证件查询
  • 建站宝盒建网站免费外贸建站平台
  • 查看网站有多少空间创建个人网站制作流程步骤
  • 品牌型网站案例网站建设怎么找到客户
  • WordPress限时账号自己的网站做优化怎么设置缓存
  • 东莞市找工作上什么网优化模型有哪些
  • 东莞网站建设乐云seo在线制作做缓网站
  • 扁平化网站特效cms 排名 wordpress
  • 室内装修工人培训学校seo顾问服务公司站长
  • 网新企业网站管理系统网页设计6种布局方式
  • 深圳大浪网站建设百度关键词收费标准
  • 创造力网站设计集团做网站优势