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

山东富泰建设工程有限公司网站信息化建设期刊网站

山东富泰建设工程有限公司网站,信息化建设期刊网站,南通企业建站系统模板,大淘客做网站视频目录 一、Libevent 概述 1.0 Libevent的安装 1.0.1 使用源码方式 1.0.2 终端命令行安装 1.1 主要特性 1.2 主要组件 1.3 Libevent 使用模型 1.4 原理 1.5 使用的基本步骤 1.5.1 初始化事件基础设施 1.5.2. 创建和绑定服务器套接字 1.5.3. 设置监听事件 1.5.4. 定义…目录 一、Libevent 概述 1.0 Libevent的安装 1.0.1 使用源码方式 1.0.2 终端命令行安装 1.1 主要特性 1.2 主要组件 1.3 Libevent 使用模型 1.4 原理 1.5 使用的基本步骤 1.5.1 初始化事件基础设施 1.5.2. 创建和绑定服务器套接字 1.5.3. 设置监听事件 1.5.4. 定义事件处理回调函数 1.5.5. 启动事件循环 1.5.6. 释放资源 二、 使用示例 三、Libevent 实现 TCP 服务器 四、Libevent 结构图 五、守护进程 5.1 基本概念面试 5.2 如何实现呢怎么理解 5.3 守护进程编程流程面试 5.4 实验 一、Libevent 概述 Libevent 是一个高效的、轻量级的事件通知库用于开发需要处理大量并发连接的网络应用程序。它提供了一种机制来执行回调函数当特定事件发生在文件描述符上或在超时发生时Libevent 可以处理不同类型的事件包括 I/O 事件、信号事件和定时事件。 1.0 Libevent的安装 1.0.1 使用源码方式 Libevent 使用源码安装的方式源码下载地址http://libevent.org/ 下载下来后将 Libevent 的压缩包拷贝到 Linux 系统中然后按照以下步骤执行 1、 打开终端并且进入到 Libevent 所在位置 2、 切换到 root 用户 3、 利用 tar 命令解压 Libevent 压缩包 4、 进入到解压开的目录中 5、 执行命令 ./configuer --prefix/usr 6、 使用 make 命令完成编译 7、 使用 make install 命令完成安装 8、 使用 ls -al /usr/lib | grep libevent 测试安装是否成功 1.0.2 终端命令行安装 切换到管理员身份sudo su 执行命令apt install libevent-dev 1.1 主要特性 跨平台支持Libevent 支持多种平台包括 Linux、BSD、Windows 和 macOS。多种后端支持Libevent 支持多种 I/O 复用后端包括 select、poll、epoll、kqueue、devpoll 和 Windows IOCP。高效的 I/O 处理通过使用适当的 I/O 复用机制如 epoll 或 kqueueLibevent 能够处理大量并发连接适用于高性能服务器开发。事件优先级Libevent 支持为事件设置优先级使得重要事件可以优先处理。线程安全Libevent 提供线程安全的 API可以在多线程环境中使用。基于 Reactor 模式的实现。 1.2 主要组件 event_base事件循环的核心用于管理所有的事件。event表示一个具体的事件比如一个文件描述符上的读写事件。bufferevent用于处理缓冲 I/O封装了事件和缓冲区的管理提供更高层次的接口。evbuffer提供灵活的缓冲区管理可以高效地读写数据。 1.3 Libevent 使用模型 把描述符和回调函数注册到libevent中让libevent检测是否有读事件发生我们此时不用管底层io复用方法是如何实现的等到事件发生就会调用我们注册的回调函数。也可以检测信号。 Libevent 通过高效的 I/O 复用机制如 epoll、kqueue 等和事件驱动模型来处理大量并发连接。这些机制允许一个线程同时监视多个文件描述符上的事件从而避免了每个连接一个线程或进程的资源开销问题。 1.4 原理 I/O 复用机制 select遍历整个文件描述符集检查每个文件描述符的状态适用于小规模并发连接。poll类似于 select但使用链表结构支持更大规模的文件描述符。epollLinux和 kqueueBSD、macOS高级的 I/O 复用机制采用事件通知模型适合处理大量并发连接。IOCPWindows基于完成端口的高效 I/O 复用机制。 事件驱动模型 Libevent 使用事件循环模型通过 event_base_dispatch() 进入事件循环等待并处理事件。每个文件描述符上的读写事件、超时事件和信号事件都会注册到事件循环中。当一个事件发生时Libevent 会调用预先定义的回调函数来处理该事件。 1.5 使用的基本步骤 1.5.1 初始化事件基础设施 在使用 Libevent 之前首先需要初始化事件基础设施即创建一个 event_base 对象。这个对象是事件循环的核心负责管理事件的分发和处理。初始化事件基础设施的目的是为了为后续的事件处理做准备确保程序能够正确地处理事件。 1.5.2. 创建和绑定服务器套接字 在服务器端需要创建一个监听套接字并将其绑定到特定的 IP 地址和端口上。这个套接字将用于接受客户端的连接请求。将服务器套接字设置为非阻塞模式可以确保服务器在等待客户端连接时不会被阻塞可以同时处理多个连接请求。 1.5.3. 设置监听事件 为监听套接字设置事件当有新的连接请求到达时触发相应的回调函数。这样可以将新的连接请求转换为事件方便后续的处理。事件驱动模型是一种高效的处理并发连接的方式通过事件处理器来处理各种事件避免了阻塞式的处理方式提高了系统的并发能力。 1.5.4. 定义事件处理回调函数 为每种事件类型定义相应的处理回调函数。例如针对新连接的事件定义一个回调函数来处理新连接针对读写事件定义相应的回调函数来处理数据的读写操作。这些回调函数是处理事件的核心逻辑通过它们来实现具体的业务逻辑。 1.5.5. 启动事件循环 调用 event_base_dispatch() 函数启动事件循环开始等待并处理事件。事件循环是 Libevent 的核心机制负责监视事件的发生并调用相应的回调函数来处理这些事件。通过事件循环可以实现高效地处理大量并发连接提高系统的并发能力和性能。 1.5.6. 释放资源 在程序结束时释放分配的事件和事件基础设施资源。这是良好的编程习惯确保程序在结束时能够正确地释放资源避免内存泄漏和资源泄漏问题。释放资源也包括关闭服务器套接字释放事件基础设施等操作。 二、 使用示例 定义两个事件一个是信号ctrlc打印信号值另一个是定时事件将这两个事件加入到Libevent中进行事件循环检测当事件发生自动的调用回调函数处理。 关键函数解释 struct event*sig_evevsignal_new(base,SIGINT,sig_cb,NULL); 第一个参数是添加到那个libevent实例中第二个参数是信号代号第三个参数是回调函数第四个参数是传给回调函数的参数。   struct event* sig_evevent_new(base,SIGINT,EV_SIGNAL,sig_cb,NULL); 展开 EV_SIGNAL信号事件 evsignal_new 和 evtimer_new都是宏他们统一的入口都是event_new函数。 Libevent 支持的事件类型 三、Libevent 实现 TCP 服务器 使用 libevent 库实现的 TCP 服务器代时将监听 socket 和连接 socket 分别生成一个 Libevent 事件指定其对应的回调函数并将其添加到 Libevent 的一个 Base 中执行事件 循环检测事件发生。客户端的代码与 select 部分客户端代码相同代码示例如下 1. #include stdio.h 2. #include stdlib.h 3. #include assert.h 4. #include string.h 5. #include unistd.h 6. #include sys/types.h 7. #include sys/socket.h 8. #include netinet/in.h 9. #include arpa/inet.h 10. #include event.h 11. 12. #define MAX_CLIENT 100 // 最大客户端数量 13. #define DATALENGTH 1024 // 数据缓冲区长度 14. 15. struct event_base *base NULL; // 全局事件基础结构 16. 17. typedef struct ClientData 18. { 19. int fd; // 客户端文件描述符 20. struct event *ev; // 客户端事件 21. } ClientData; 22. 23. // 初始化客户端数据 24. void InitClients(ClientData clients[]) 25. { 26. int i 0; 27. for (; i MAX_CLIENT; i) 28. { 29. clients[i].fd -1; // -1表示未使用 30. clients[i].ev NULL; // 初始化事件指针为空 31. } 32. } 33. 34. // 插入客户端数据 35. void InsertToClients(ClientData clients[], int fd, struct event *ev) 36. { 37. int i 0; 38. for (; i MAX_CLIENT; i) 39. { 40. if (clients[i].fd -1) 41. { 42. clients[i].fd fd; // 设置客户端文件描述符 43. clients[i].ev ev; // 设置客户端事件 44. break; // 找到一个空位后跳出循环 45. } 46. } 47. } 48. 49. // 删除客户端数据 50. struct event *DeleteOfClients(ClientData clients[], int fd) 51. { 52. int i 0; 53. for (; i MAX_CLIENT; i) 54. { 55. if (clients[i].fd fd) 56. { 57. clients[i].fd -1; // 将文件描述符重置为-1 58. return clients[i].ev; // 返回相应的事件指针 59. } 60. } 61. 62. return NULL; // 未找到时返回NULL 63. } 64. 65. // 初始化 socket 66. int InitSocket() 67. { 68. int sockfd socket(AF_INET, SOCK_STREAM, 0); // 创建套接字 69. if (sockfd -1) return -1; // 出错返回-1 70. 71. struct sockaddr_in saddr; 72. memset(saddr, 0, sizeof(saddr)); // 清空地址结构 73. saddr.sin_family AF_INET; // 设置地址族为IPv4 74. saddr.sin_port htons(6000); // 设置端口号网络字节序 75. saddr.sin_addr.s_addr inet_addr(127.0.0.1); // 设置IP地址 76. 77. int res bind(sockfd, (struct sockaddr*)saddr, sizeof(saddr)); // 绑定套接字 78. if (res -1) return -1; // 出错返回-1 79. 80. res listen(sockfd, 5); // 开始监听 81. if (res -1) return -1; // 出错返回-1 82. 83. return sockfd; // 返回套接字文件描述符 84. } 85. 86. // 客户端事件处理函数 87. void client_fun(int fd, short event, void *arg) 88. { 89. ClientData *clients (ClientData*)arg; 90. 91. char buff[DATALENGTH] { 0 }; 92. int n recv(fd, buff, DATALENGTH - 1, 0); // 接收数据 93. if (n 0) 94. { 95. struct event *ev DeleteOfClients(clients, fd); // 删除客户端 96. event_free(ev); // 释放事件 97. printf(A Client Disconnect\n); // 打印断开连接消息 98. return; 99. } 100. 101. printf(%d:%s\n, fd, buff); // 打印接收到的数据 102. send(fd, OK, 2, 0); // 发送回应 103. } 104. 105. // 服务器套接字事件处理函数 106. void sockfd_fun(int fd, short event, void *arg) 107. { 108. ClientData *clients (ClientData*)arg; 109. struct sockaddr_in caddr; 110. socklen_t len sizeof(caddr); 111. int c accept(fd, (struct sockaddr*)caddr, len); // 接受客户端连接 112. if (c 0) 113. { 114. return; // 出错直接返回 115. } 116. 117. struct event *ev event_new(base, c, EV_READ | EV_PERSIST, client_fun, arg); // 创建新事件 118. InsertToClients(clients, c, ev); // 插入客户端数据 119. event_add(ev, NULL); // 添加事件到事件基础结构 120. printf(A client Link\n); // 打印连接成功消息 121. } 122. 123. 124. int main() 125. { 126. int sockfd InitSocket(); // 初始化服务器套接字 127. assert(sockfd ! -1); // 断言检查套接字是否创建成功 128. 129. ClientData clients[MAX_CLIENT]; // 定义客户端数据数组 130. InitClients(clients); // 初始化客户端数据 131. 132. base event_init(); // 初始化事件基础结构 133. 134. struct event *ev event_new(base, sockfd, EV_READ | EV_PERSIST, sockfd_fun, (void*)clients); // 创建服务器套接字事件 135. event_add(ev, NULL); // 添加事件到事件基础结构 136. 137. event_base_dispatch(base); // 进入事件循环 138. event_free(ev); // 释放事件 139. event_base_free(base); // 释放事件基础结构 140. 141. exit(0); // 退出程序 142. }这是一个简单的基于Libevent库的服务器程序示例。它创建一个监听端口6000通过事件循环处理客户端连接和数据传输。服务器能够同时处理多个客户端连接每个客户端连接都会被添加到一个事件中并且在接收到数据时会调用相应的回调函数来处理。代码中定义了ClientData结构体用于保存客户端的文件描述符和事件并提供了初始化、插入和删除客户端的函数。主函数初始化服务器套接字和事件基础结构设置事件处理函数并进入事件循环直到程序结束。  四、Libevent 结构图 五、守护进程 5.1 基本概念面试 守护进程Daemon是一种在后台运行的计算机程序不直接与用户交互。通常它们在系统启动时启动并持续运行直到系统关闭。这类进程通常执行系统级任务比如日志记录、处理网络请求、管理打印任务等。守护进程的几个主要特点包括 后台运行守护进程通常在后台运行不会直接与用户进行交互。它们可以在系统引导时启动并在整个系统运行期间保持活动状态。 长时间运行守护进程通常需要长时间运行不会因为完成某个任务后就退出而是持续运行以处理多个任务或事件。 独立运行一旦启动守护进程通常独立于启动它的终端甚至终端关闭后它们仍然可以继续运行。 系统服务守护进程提供各种系统服务例如网络服务如HTTP服务器、FTP服务器、系统任务如cron调度器、设备管理如打印机服务等。 命名规范在Unix和类Unix系统中守护进程的名字通常以字母“d”结尾例如httpd处理HTTP请求、sshd处理SSH连接、crond管理定时任务。 5.2 如何实现呢怎么理解 我们跟系统之间每次打开一个终端交互的时候等于和内核之间建立了一个会话。一旦关闭终端这个会话就会结束。会话中运行的所有进程都会被结束而我们希望这个进程服务进程能够在后台长久的运行所以我们在关闭会话的时候那么我们就不能关闭这个进程。这个进程不能关闭如何解决呢 我们就必须让这个进程脱离这个会话它不属于这个会话那你关闭它就不会结束这个进程了。举个例子假如你们是三班我说三班同学都出去那三班所有人都出去但是我现在不想让小明出去我说小明你以后就是四班的人然后我说三班人都出去你们都出去小明是不是就被留下来了就跟这个道理一样就现在我们需要这个进程长久的执行但是我们在关闭这个终端的时候所有会话也就这个会话中所属的所有进程全部被结束那就只能怎么办让你不属于这个会话但你还得有个会话啊。所以这个就是创建一个新会话就等于把你放到新会话中然后我把原来会话结束新会话我们保留下来那为啥原来的会话不能留下来你这个新会话可留下来因为新会话不附着于任何终端。我们之前跟系统之间交互是不是都是打开一个终端那现在这个地方创建的时候我们这个会话并没有依存于这个终端所以关闭这个终端这个会话它不结束。我们每一次跟系统交互啊通过打开这个终端来和它交互的时候那么我们这个会话你可以理解为附着于这个终端之上如果这个终端关闭这个会话是不是就结束了但是我们内部通过程序去创建是我们不依附于那个终端所以关闭那个终端我们的会话它不结束。 如下图所示假如你打开了这么一个终端。我们会为此创建一个会话这个会话与这个终端相关联终端一旦关闭该会话就结束了。在这个会话中我们要执行一个一个的命令其实这些命令进程呢又是以进程组的形式呈现了也就是说我们其实管理它的时候是先创建一个进程组然后再去执行我们的命令我们用三角形代表进程或者咱们的命令。比如说你执行ls那么你执行ls的时候它不止创建了一个进程还创建一个进程组只不过该进程组中只有你一个人。那这个进程的结束这个进程组也就随时结束了但有时候咱们可以fork或者把多个进程合在一起去执行所以呢我们也可能在这个地方发现这个进程组中有多个进程。那多个进程的话我们是这样的第一个进程它是我们的组长进程我们会用它的ID号标识整个进程组当然它也可能里头只有两个进程都有可能存在也可能是一个并且大部分情况下可能这个进程组都只有一个进程。解释一个概念会话。怎么表示这个会话呢我们让会话中的第一个进程用它的ID号来标识这个会话所以我们会有个概念叫做会话首进程就是会话首进程的PID就是会话ID。这个进程的PID用来干什么呢啊用来标识该会话。那么这个进程组又是什么呢它就有一个组长进程这个组长进程就是我们在这个进程组中第一个运行的那个进程。你也可以理解为我们当前进程的PID如果等于我们的组长ID等于我们进程。组的ID那你就是我们的组长也可以理解为我们使用这个组长进程ID出来标识整个进程组。 5.3 守护进程编程流程面试 fork() 退出父进程 setsid() fork() 退出父进程 chdir(/) umask(0) close() 第一次为啥要fork? 因为我们要把当前进程要拿出来重新创建一个会话那么这个时候呢我们会成为整个会话中的第一个进程就成为了会话首进程。要用我们的ID标识整个会话其次呢我们也是整个会话中是不是运行的第一个进程那这个进程是本身也得是一个进程组对不对也要生成一个进程组也就说我们要用这个进程ID号来命名一个进程组它会变成我们的组长进程那么我们思考一下。我们这个进程如果在原来的会话中本来就是一个进程组的组长那么我们把它拿出来如果去调用sets ID创建新会话那么它在新会话中是不是也是一个继承组的组长那等于就是我要用这个进程的一个ID是不是要标识两个继承组这就不合适了。所以我怎么办呢我需要挑一个普通的组员进程把它拿出来啊然后让它能变成这个新会话中的首进程这样我们是不是可以用这个组员进程ID来标识我们一个新的进程组就比如说咱们班有两个组小明是一个组的组长我现在要成立第二个组我能不能再把小明揪出来做第二个组我是不是要揪一个组员出来做第二个组所以在这块一样就是我们如果只有一个进程的话那我们自己本来就是一个进程组的组长我们已经用我们的ID号是标识一个进程组了。但是一旦我们把它拿出来调用set SD去创建新会话去成立第二个会话那么它是不是在第二个会话中那么它还会扮演着该会话内部一个进程的进程组因为那个会话中就他一个进程嘛对不对他自身肯定还要有一个组来管理他就是他自己的ID的。创建的一个组但是已经用他ID是不是在旧的会话中是不是已经创建过一个组了所以我们第一步先fork就会有个什么结果呢退出父进程那我们留下是不是一个子进程可以这么讲留下这个子进程。肯定是一个组员进程。所以们就保证我们先拿到一个组员组员再调sets ID就会创建一个新会话那这个组员就会变成新会话的首进程。同时也是这个新会话中目前出现第一个进行组的组长那然后我们再fork一次那么就会使我们失去组长的身份失去首会话进程的身份。因为你fork的一个子进程嘛。你又变成子进程了嘛这样父进程就丢掉了嘛。为什么要做这个事情呢这个事情其实可以不做啊那么有些书上这么讲的就是它可以跟一个终端就是再通过执行相应的操作。关联起来但是如果你不是会话首进程的话你没有这个能力所以就等于让它失去这个能力防止它你不小心在于哪个终端去执行了某某个操作。去关联起来就比如说某个函数一调可以附着于某个终端对吧因为我们希望你是不是后面要长久运行呢所以把这个操作一执行的话那么你就失去了会话手机上的身份那么就不用再担心你会不小心又掉了某个操作把你跟哪个终端去附着在一起的比如我们在这儿调创建新的话是不是好不容易从原来终端中但是脱离出来了掉色台是从原来终端中所在这个会话中就脱离出来了那你就不要把你再去和其他已打开终端再去关联了你一关联人家一关把你识别就关掉了。它是起这么一个作用但你不做这样操作是不做第三步也不影响大部分人也不会去干这样的事情。有些资料上就不做第三步有些资料上做了所以做你就知道就这个原因他不做他也对 然后现在就变成变成新会话中的一个会话首进程而且是个进程组的组长然后通过第三步一执行我们就失去了会话首进程和进程组长身份我们就变成一个普通组员进程就让他去长久执行。因为我们运行时间比较长我们把当前的工作路径要切换到根目录底下不能把它出现在一些可被卸载的目录上就比如说我们如果在U盘中运行一个程序。你一旦把这个U盘想要弹出这个程序还在运行没结束你会发现U盘是弹不出去的这跟这个道理一样因为这个路径是不是正在被你用因为实物进程运行时间比较长所以不管从哪执行我们都把它的工作路径直接调到根目录底下因为不可能有人去卸载根。当然你如果整个目录也并不会被卸载你没做第四步其实也不影响所以一般我们还是把它做上就行了。 然后这个是清除掩码因为你挪到根目录或者说你在啊某一个固定的目录底下。你也不知道那个木水下线的这个掩码是多少那我们把它清零就行了不要把不用的描述符关闭就可以你后面想要用哪些你再打开哪些就行了。那这样一套流程走下来之后那么这个程序就脱离了这个终端在后台运行嘛然后呢它就可以长久的执行了只要你不q它它就不结束。因为它不负责终端关终端它还在运行只要程序自己不想退出你也不q它它就可以一直在后台运行它也不需要跟你进行交互因为这个close点标准输入标准输出标准错误输入全都关闭了。你也别想让他让他打印信息了那么他如果想要有一些信息提示你怎么办因为这个程序总得有输出。他一般会写日志文件磁盘上创建一个文件所以服务器一般都会有一个日志啊写日志的这么一个。文件来存放一些发生的事情同时还得有个日志的进程专门用来啊管理写这个日志啊我系统几点几分启动现在几点几分我访问数据库哪个用户登录就是这些我觉得我需要记录就把它存起来我这个函数报error了我把它存一下。本来这种咱们就打屏幕因为现在没屏幕让你用了。而且管理员不可能一直盯着屏幕去看写到日志中的话是不是永久存到磁盘上了比如说啊管理员过了两天想看那你过两天再把它打开看就行了。你要在屏幕上的话有新信息把它不就刷新了吗你就观察不到了啊所以这样就可以做。 fork() 退出父进程 fork()系统调用会创建一个子进程子进程是父进程的副本。在创建子进程后父进程和子进程会在fork()调用的返回值处分别得到不同的值父进程得到子进程的进程IDPID而子进程得到0。这样父进程和子进程可以通过返回值来区分彼此。在守护进程创建过程中父进程负责创建子进程然后退出让子进程继续独立运行。原因父进程退出后子进程会成为孤儿进程并被init进程接管从而确保守护进程不会与任何终端关联。 setsid() setsid()系统调用会创建一个新的会话并将调用进程设置为该会话的领导。该进程成为新会话的唯一成员没有控制终端。原因守护进程需要脱离控制终端以免受到终端的影响setsid()调用可以确保守护进程完全独立于终端会话。 fork() 退出父进程 这一步是为了确保守护进程不会重新获取控制终端。在已经创建了新会话的前提下再次调用fork()是为了防止守护进程通过setsid()成为会话领导后再次获取控制终端。原因通过再次调用fork()确保守护进程不会意外地重新获取控制终端。 chdir(/) 将当前工作目录更改为根目录/确保守护进程不会占用任何文件系统。原因避免守护进程的当前工作目录影响其他进程的操作也防止某些文件系统被锁定。 umask(0) 将文件创建掩码设置为0即不屏蔽任何权限确保守护进程创建的文件具有完全开放的权限。原因避免文件权限问题确保守护进程创建的文件具有所需的权限。 close() 关闭所有从父进程继承的文件描述符包括标准输入、输出和错误描述符stdin、stdout、stderr。原因关闭继承的文件描述符以防止守护进程意外地使用这些文件描述符与终端或其他进程进行交互同时也释放了不需要的系统资源。 5.4 实验 写一个程序让它每隔五秒钟向文件中写入当前时间以此来模拟这个程序一直在后台执行。 至此已经讲解完毕篇幅较长慢慢消化以上就是全部内容请务必掌握创作不易欢迎大家点赞加关注评论您的支持是我前进最大的动力下期再见
http://www.w-s-a.com/news/824333/

相关文章:

  • 网站怎样建设才叫人性化宣传
  • 济南网站制作方案做淘客网站备案
  • h5企业网站只做做php门户网站那个系统好
  • 长春阿凡达网站建设建网站如果不买域名别人能不能访问
  • 佛山网站建设策划东莞建设工程交易网
  • 制作公众号网站开发濮阳建网站
  • 屏南网站建设兼职旅游网站建设方案两百字
  • 最牛的网站建设网站建设的规模设想
  • 马云之前做的网站企业形象策划
  • ie9网站后台编辑器代发qq群发广告推广
  • 百度怎样建立一个网站嘉兴高端网站定制
  • 国外设计网站怎么进入电子网站建设前台设计
  • 中方建设局网站济南网站建设公司电子商务网站
  • 如何做网站编辑 沒技术济南企业做网站推广网站
  • 网站模板 百科北京中高风险地区最新名单最新
  • 高校网站建设前言做公众号的公司是什么公司
  • 网站备案怎么登陆短视频培训学校
  • 百度图片点击变网站是怎么做的北京市建设工程质量监督站网站
  • 在线建站模板重庆网站建设大概需要多少钱
  • 建设网站公司电话号码wordpress 即时通讯
  • 网站设计用的技术拓者吧室内设计网app
  • 河北seo优化_网络建设营销_网站推广服务 - 河北邢台seo网站建设运行情况报告
  • 建设银行内部网站6画册设计是什么
  • 网站建设什么价格网站下拉菜单怎么做
  • flash型网站微信公众号运营策划
  • 想建设个网站怎么赚钱国外学校网站设计
  • 网站设计网页设计系统没有安装wordpress
  • 建网站做哪方面公司百度官网优化
  • 山西网站seo网站采集信息怎么做
  • 同江佳木斯网站建设seo学徒培训