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

网站制作开发公司广告平台网站有哪些

网站制作开发公司,广告平台网站有哪些,python 类似wordpress,苏州集团网站制作设计目录 一、概述与基础概念 1.1 套接字(Socket)概念 1.2 底层原理与网络协议 1.2.1 网络协议 1.2.2 套接字工作原理 二、C套接字编程核心技术 2.1 套接字编程的基本步骤 2.2 套接字编程详细实现 2.2.1 创建套接字 2.2.2 绑定地址 2.2.3 监听和接…

目录

一、概述与基础概念

1.1 套接字(Socket)概念

1.2 底层原理与网络协议

1.2.1 网络协议

1.2.2 套接字工作原理

二、C++套接字编程核心技术

2.1 套接字编程的基本步骤

2.2 套接字编程详细实现

2.2.1 创建套接字

2.2.2 绑定地址

2.2.3 监听和接受连接(服务端)

2.2.4 客户端连接

2.2.5 发送和接收数据

2.2.6 关闭套接字

2.3 经典实例:TCP客户端和服务器

2.3.1 TCP服务器

2.3.2 TCP客户端

运行结果

三、深入理解与高级应用

3.1 异步I/O与事件驱动编程

3.2 高效并发编程

3.3 使用Boost.Asio进行异步编程

完整代码示例:使用Boost.Asio进行异步TCP服务器

BoostServer.cpp

四、核心技术及高级话题

4.1 同步I/O与异步I/O的选择

4.2 多线程与事件驱动模型

4.3 高效网络编程的关键技术

4.4 使用C++11/14/17/20新特性优化网络编程

五、实例:高效异步HTTP服务器

5.1 异步HTTP服务器

运行结果

六、拓展思考

1、套接字(Socket)是什么?它包括哪些核心内容?

套接字的定义

套接字的核心内容

1. 套接字类型

2. 地址族

3. 套接字的基本操作

套接字的高级内容

2、套接字 socket是基于哪个网络协议的?是TCP还是Http?

总结


网络编程是现代软件开发的重要领域,广泛应用于客户端-服务器应用、分布式系统和互联网应用开发中。C++作为一门强大且高效的编程语言,在进行低层次、高性能网络编程时有显著优势。本文将深入剖析C++网络编程中的套接字(Socket)开发技术,详细讲解其概念、底层原理、网络协议知识、本质及需要掌握的核心点、实现方式等,同时结合经典实例进行解析。

一、概述与基础概念

1.1 套接字(Socket)概念

概念:套接字(Socket)是网络编程中用于描述网络连接的端点,是操作系统提供的用于网络通信的基础抽象。它可以看作是网络中的“文件”,通过对套接字的操作实现数据的发送和接收。

核心点

  • 类型:主要包括流套接字(SOCK_STREAM)和数据报套接字(SOCK_DGRAM),分别对应TCP和UDP协议。
  • 地址:由IP地址和端口号组成,用于标识网络中的设备和应用。

1.2 底层原理与网络协议

1.2.1 网络协议

IP地址:标识网络中的主机,分为IPv4(如192.168.1.1)和IPv6(如2001:db8::1)地址。

端口号:标识主机上的应用程序,范围为0到65535。常见的端口号如HTTP的80端口、HTTPS的443端口等。

TCP/IP协议族:互联网的基础协议族,包含传输层的TCP和UDP、网络层的IP等。

  • TCP(传输控制协议):提供可靠的字节流服务,包括连接建立、数据传输、连接终止等过程。TCP通过三次握手建立连接,四次挥手终止连接。
  • UDP(用户数据报协议):提供不可靠的消息传递服务,数据报可能无序到达或丢失。UDP适用于实时性要求较高的应用,如视频传输、在线游戏等。
1.2.2 套接字工作原理

套接字是一种抽象层,使得应用程序能够通过操作系统提供的API进行网络通信。它包含以下基本操作:

  • 创建:通过系统调用创建套接字。
  • 绑定:将套接字绑定到特定的IP地址和端口。
  • 监听:在服务端,套接字监听来自客户端的连接请求。
  • 连接:在客户端,套接字连接到服务端的指定地址和端口。
  • 发送/接收:通过套接字发送和接收数据。
  • 关闭:关闭套接字,释放系统资源。

二、C++套接字编程核心技术

2.1 套接字编程的基本步骤

  1. 创建套接字
  2. 绑定地址
  3. 监听(服务端)
  4. 接受连接(服务端)
  5. 连接(客户端)
  6. 发送和接收数据
  7. 关闭套接字

2.2 套接字编程详细实现

2.2.1 创建套接字
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {perror("socket creation failed");exit(EXIT_FAILURE);
}

解析

  • socket(AF_INET, SOCK_STREAM, 0):创建一个TCP套接字。AF_INET表示使用IPv4,SOCK_STREAM表示使用TCP协议。
  • 返回值:成功时返回套接字文件描述符,失败时返回-1。
2.2.2 绑定地址
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(PORT);if (bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {perror("bind failed");close(sockfd);exit(EXIT_FAILURE);
}

解析

  • struct sockaddr_in:定义IP地址和端口,sin_family设为AF_INETsin_addr.s_addr设为INADDR_ANY表示接受任何IP地址,sin_port设为端口(通过htons函数转换为网络字节序)。
  • bind:将地址绑定到套接字。
2.2.3 监听和接受连接(服务端)
if (listen(sockfd, 5) < 0) {perror("listen failed");close(sockfd);exit(EXIT_FAILURE);
}struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int newsockfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_len);
if (newsockfd < 0) {perror("accept failed");close(sockfd);exit(EXIT_FAILURE);
}

解析

  • listen:将套接字置于监听模式,准备接受连接。第二个参数为连接队列的最大长度。
  • accept:接受客户端连接,返回新的套接字用于通信。client_addr保存客户端地址信息。
2.2.4 客户端连接
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
if (inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr) <= 0) {perror("invalid address");exit(EXIT_FAILURE);
}if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {perror("connect failed");close(sockfd);exit(EXIT_FAILURE);
}

解析

  • inet_pton:将字符串形式的IP地址转换为struct in_addr
  • connect:将套接字连接到指定的服务器地址和端口。
2.2.5 发送和接收数据
const char* message = "Hello, Server!";
send(sockfd, message, strlen(message), 0);char buffer[1024];
int n = recv(sockfd, buffer, sizeof(buffer), 0);
buffer[n] = '\0';
printf("Received: %s\n", buffer);

解析

  • send:发送数据,第四个参数为标志位,通常为0。
  • recv:接收数据,返回接收的字节数。
2.2.6 关闭套接字
close(sockfd);

2.3 经典实例:TCP客户端和服务器

2.3.1 TCP服务器
#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>#define PORT 8080int main() {int server_fd, new_socket;struct sockaddr_in address;int opt = 1;int addrlen = sizeof(address);char buffer[1024] = {0};const char* hello = "Hello from server";// 创建套接字if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {perror("socket failed");exit(EXIT_FAILURE);}// 强制绑定端口if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {perror("setsockopt");close(server_fd);exit(EXIT_FAILURE);}// 绑定地址address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port = htons(PORT);if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) < 0) {perror("bind failed");close(server_fd);exit(EXIT_FAILURE);}// 监听连接if (listen(server_fd, 3) < 0) {perror("listen");close(server_fd);exit(EXIT_FAILURE);}// 接受客户端连接if ((new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen)) < 0) {perror("accept");close(server_fd);exit(EXIT_FAILURE);}// 读取客户端数据int valread = read(new_socket, buffer, 1024);printf("%s\n", buffer);// 发送数据到客户端send(new_socket, hello, strlen(hello), 0);printf("Hello message sent\n");// 关闭套接字close(new_socket);close(server_fd);return 0;
}

解析

  • 创建套接字socket(AF_INET, SOCK_STREAM, 0)
  • 绑定地址bind
  • 监听连接listen
  • 接受连接accept
  • 读取数据read
  • 发送数据send
  • 关闭套接字close
2.3.2 TCP客户端
#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>#define PORT 8080int main() {int sock = 0, valread;struct sockaddr_in serv_addr;const char* hello = "Hello from client";char buffer[1024] = {0};// 创建套接字if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {perror("Socket creation error");return -1;}serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(PORT);// 将IP地址转换成二进制形式if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {perror("Invalid address/ Address not supported");return -1;}// 连接服务器if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {perror("Connection Failed");return -1;}// 发送数据到服务器send(sock, hello, strlen(hello), 0);printf("Hello message sent\n");// 读取服务器响应valread = read(sock, buffer, 1024);printf("%s\n", buffer);// 关闭套接字close(sock);return 0;
}

解析

  • 创建套接字socket(AF_INET, SOCK_STREAM, 0)
  • 连接服务器connect
  • 发送数据send
  • 读取数据read
  • 关闭套接字close

运行结果

  1. 启动服务器:

    ./server
    

    输出

    Hello from client
    Hello message sent
    
  2. 启动客户端:

    ./client
    

    输出

    Hello message sent
    Hello from server
    

三、深入理解与高级应用

3.1 异步I/O与事件驱动编程

异步I/O:允许程序在等待I/O操作完成时继续执行其他任务,提高程序的并发性能。实现方式包括:

  • 多线程:每个I/O操作分配一个线程处理。
  • 事件驱动:使用事件循环处理I/O事件,例如selectpollepoll等。
3.2 高效并发编程

多线程网络编程

  • 线程同步:避免多个线程同时访问共享资源,使用互斥锁、条件变量等。
  • 线程池:复用线程,减少线程创建和销毁的开销,提高性能。

实例:使用线程池处理多个客户端连接。

#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>#define PORT 8080std::mutex mtx;  // 互斥锁用于保护共享资源
std::condition_variable cv;  // 条件变量用于线程间同步
std::queue<int> clients;  // 用于存储待处理的客户端套接字// 处理客户端连接的函数
void handle_client(int client_sock) {char buffer[1024];int n = recv(client_sock, buffer, sizeof(buffer), 0);  // 接收客户端消息if (n > 0) {buffer[n] = '\0';  // 添加字符串终止符std::cout << "Received: " << buffer << std::endl;const char* response = "Message received";send(client_sock, response, strlen(response), 0);  // 发送响应给客户端}close(client_sock);  // 关闭客户端连接
}// 工作线程函数,用于处理客户端连接
void worker() {while (true) {int client_sock;{std::unique_lock<std::mutex> lock(mtx);  // 获取锁cv.wait(lock, [] { return !clients.empty(); });  // 等待条件变量通知client_sock = clients.front();  // 从队列中取出客户端套接字clients.pop();  // 移除队列中的套接字}handle_client(client_sock);  // 处理客户端连接}
}int main() {int server_sock = socket(AF_INET, SOCK_STREAM, 0);  // 创建TCP套接字if (server_sock < 0) {perror("socket creation failed");exit(EXIT_FAILURE);}struct sockaddr_in server_addr;memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_family = AF_INET;  // 使用IPv4server_addr.sin_addr.s_addr = INADDR_ANY;  // 绑定所有可用的网络接口server_addr.sin_port = htons(PORT);  // 绑定端口if (bind(server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {perror("bind failed");close(server_sock);exit(EXIT_FAILURE);}if (listen(server_sock, 5) < 0) {  // 设置监听队列的最大长度为5perror("listen failed");close(server_sock);exit(EXIT_FAILURE);}// 创建多个工作线程std::vector<std::thread> workers;for (int i = 0; i < 4; ++i) {workers.emplace_back(worker);  // 启动工作线程}while (true) {struct sockaddr_in client_addr;socklen_t client_len = sizeof(client_addr);int client_sock = accept(server_sock, (struct sockaddr*)&client_addr, &client_len);  // 接受客户端连接if (client_sock < 0) {perror("accept failed");continue;}{std::lock_guard<std::mutex> lock(mtx);  // 获取锁clients.push(client_sock);  // 将客户端套接字添加到队列中}cv.notify_one();  // 通知一个工作线程}for (auto& t : workers) {t.join();  // 等待所有工作线程结束}close(server_sock);  // 关闭服务器套接字return 0;
}

 

3.3 使用Boost.Asio进行异步编程

Boost.Asio 是一个强大且灵活的库,提供了跨平台的异步I/O操作,支持多平台。我们继续讨论如何使用Boost.Asio实现一个高效的异步TCP服务器。

完整代码示例:使用Boost.Asio进行异步TCP服务器

BoostServer.cpp
#include <boost/asio.hpp>
#include <iostream>
#include <memory>
#include <utility>using boost::asio::ip::tcp;// 会话类,用于管理单个客户端连接
class Session : public std::enable_shared_from_this<Session> {
public:explicit Session(tcp::socket socket): socket_(std::move(socket)) {}// 开始会话void start() {do_read();  // 开始读取数据}private:// 异步读取数据void do_read() {auto self(shared_from_this());socket_.async_read_some(boost::asio::buffer(data_, max_length),[this, self](boost::system::error_code ec, std::size_t length) {if (!ec) {std::cout << "Received: " << data_ << std::endl;do_write(length);  // 读取完成后写入数据}});}// 异步写入数据void do_write(std::size_t length) {auto self(shared_from_this());boost::asio::async_write(socket_, boost::asio::buffer(data_, length),[this, self](boost::system::error_code ec, std::size_t /*length*/) {if (!ec) {do_read();  // 写入完成后继续读取数据}});}tcp::socket socket_;  // 套接字enum { max_length = 1024 };char data_[max_length];  // 数据缓冲区
};// 服务器类,用于管理客户端连接
class Server {
public:Server(boost::asio::io_context& io_context, short port): acceptor_(io_context, tcp::endpoint(tcp::v4(), port)) {do_accept();  // 开始接受连接}private:// 异步接受连接void do_accept() {acceptor_.async_accept([this](boost::system::error_code ec, tcp::socket socket) {if (!ec) {std::make_shared<Session>(std::move(socket))->start();}do_accept();  // 继续接受下一次连接});}tcp::acceptor acceptor_;  // 接受器,用于监听连接
};int main(int argc, char* argv[]) {try {if (argc != 2) {std::cerr << "Usage: BoostServer <port>\n";return 1;}boost::asio::io_context io_context;  // IO上下文Server s(io_context, std::atoi(argv[1]));  // 创建服务器io_context.run();  // 运行IO上下文} catch (std::exception& e) {std::cerr << "Exception: " << e.what() << "\n";}return 0;
}

 

解析

  1. Session类:管理单个客户端连接。
    • do_read:异步读取数据,使用async_read_some方法。
    • do_write:异步写入数据,使用async_write方法。
  2. Server类:管理所有客户端连接。
    • do_accept:异步接受新的连接,使用async_accept方法。
  3. main函数:创建io_contextServer实例,调用io_context.run()运行事件循环。

四、核心技术及高级话题

4.1 同步I/O与异步I/O的选择

同步I/O

  • 简单直接,易于编程和调试。
  • 适合处理少量并发连接。

异步I/O

  • 提高并发性能,适合高并发场景。
  • 编程复杂度较高,需要处理回调、状态管理等。
4.2 多线程与事件驱动模型

多线程模型

  • 每个连接分配一个线程处理。
  • 线程同步开销大,线程数量有限制。

事件驱动模型

  • 使用事件循环处理I/O事件。
  • 无需大量线程,仅需少量线程处理所有连接。
4.3 高效网络编程的关键技术
  • I/O复用:如selectpollepoll,实现单线程高效处理多个连接。
  • 零拷贝:减少内存拷贝,提高数据传输效率。
  • 内存池:复用内存,减少内存分配和释放开销。
  • 负载均衡:分配连接到不同服务器,均衡负载,提高系统吞吐量。
4.4 使用C++11/14/17/20新特性优化网络编程
  • 智能指针:如std::shared_ptrstd::unique_ptr,管理动态内存,避免内存泄漏。
  • lambda表达式:简化回调函数编写。
  • std::thread:标准多线程库,简化线程创建和管理。
  • std::async:异步任务执行,简化异步编程。

五、实例:高效异步HTTP服务器

5.1 异步HTTP服务器

使用Boost.Asio实现一个高效的异步HTTP服务器:

#include <boost/asio.hpp>
#include <iostream>
#include <memory>
#include <utility>using boost::asio::ip::tcp;class HttpSession : public std::enable_shared_from_this<HttpSession> {
public:explicit HttpSession(tcp::socket socket): socket_(std::move(socket)) {}void start() {do_read();}private:void do_read() {auto self(shared_from_this());socket_.async_read_some(boost::asio::buffer(buffer_),[this, self](boost::system::error_code ec, std::size_t length) {if (!ec) {handle_request(length);}});}void handle_request(std::size_t length) {std::string data(buffer_.data(), length);std::cout << "Request: " << data << std::endl;std::string response = "HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, world!";auto self(shared_from_this());boost::asio::async_write(socket_, boost::asio::buffer(response),[this, self](boost::system::error_code ec, std::size_t /*length*/) {if (!ec) {socket_.shutdown(tcp::socket::shutdown_both, ec);}});}tcp::socket socket_;std::array<char, 8192> buffer_;
};class HttpServer {
public:HttpServer(boost::asio::io_context& io_context, short port): acceptor_(io_context, tcp::endpoint(tcp::v4(), port)) {do_accept();}private:void do_accept() {acceptor_.async_accept([this](boost::system::error_code ec, tcp::socket socket) {if (!ec) {std::make_shared<HttpSession>(std::move(socket))->start();}do_accept();});}tcp::acceptor acceptor_;
};int main(int argc, char* argv[]) {try {if (argc != 2) {std::cerr << "Usage: HttpServer <port>\n";return 1;}boost::asio::io_context io_context;HttpServer server(io_context, std::atoi(argv[1]));io_context.run();} catch (std::exception& e) {std::cerr << "Exception: " << e.what() << "\n";}return 0;
}

 

解析

  1. HttpSession类:管理单个HTTP会话。
    • do_read:异步读取HTTP请求。
    • handle_request:处理HTTP请求,生成响应。
    • do_write:异步发送HTTP响应。
  2. HttpServer类:管理所有HTTP会话。
    • do_accept:异步接受新的HTTP连接。
  3. main函数:创建io_contextHttpServer实例,调用io_context.run()运行事件循环。

运行结果

  1. 启动HTTP服务器:

    ./HttpServer 8080
    
  2. 使用浏览器或curl访问服务器:

    curl http://localhost:8080

         输出

Hello, world!

六、拓展思考

1、套接字(Socket)是什么?它包括哪些核心内容?

套接字(Socket)是计算机网络编程中一个重要的概念,它提供了一种通信的抽象,使得程序可以通过网络进行数据传输。套接字在应用层和传输层之间起到了桥梁作用,使得不同主机上的应用程序能够进行通信。换句话说,套接字是网络通信的端点,负责处理网络协议栈中的底层细节。

套接字的定义

套接字是一个网络编程接口,允许程序发送和接收数据,通过IP地址和端口号唯一标识网络中的通信端点。套接字可以基于多种传输协议进行操作,最常见的有TCP(传输控制协议)和UDP(用户数据报协议)。

套接字的核心内容

套接字编程涉及多个核心概念和操作步骤,下面详细介绍这些内容:

1. 套接字类型
  • SOCK_STREAM:使用TCP协议,提供可靠的面向连接的通信。
  • SOCK_DGRAM:使用UDP协议,提供不可靠的无连接的通信。
  • SOCK_RAW:使用原始套接字,允许直接访问底层协议,如IP协议,通常用于网络测试和低层次的网络编程。
2. 地址族
  • AF_INET:IPv4地址族。
  • AF_INET6:IPv6地址族。
  • AF_UNIX:本地通信的Unix套接字。
3. 套接字的基本操作
  • 创建套接字:使用socket()系统调用创建一个套接字。
  • 绑定地址:使用bind()将套接字绑定到本地地址和端口。
  • 监听(仅用于TCP服务器):使用listen()将套接字置于监听模式,等待客户端连接。
  • 接受连接(仅用于TCP服务器):使用accept()接受客户端连接,返回新的套接字用于通信。
  • 连接(仅用于TCP客户端):使用connect()将套接字连接到服务器地址。
  • 发送数据:使用send()sendto()发送数据。
  • 接收数据:使用recv()recvfrom()接收数据。
  • 关闭套接字:使用close()关闭套接字,释放资源。
套接字的高级内容
  • 非阻塞模式:套接字可以设置为非阻塞模式,使得I/O操作不会阻塞程序执行。
  • 多线程/多进程:使用多线程或多进程处理多个客户端连接,提高并发性能。
  • 异步I/O:使用异步I/O操作,如selectpollepoll或Boost.Asio,实现高效的事件驱动编程。
  • 安全套接字:使用SSL/TLS加密通信,确保数据传输的安全性。

概括总结

        套接字(Socket)是网络编程中关键的抽象和接口,提供了通过网络进行数据传输的基本功能。理解和掌握套接字的核心内容和操作步骤是进行网络编程的基础。通过深入学习和实践,开发者可以灵活地使用套接字进行各种网络应用的开发,从简单的客户端-服务器通信到复杂的分布式系统。

 

2、套接字 socket是基于哪个网络协议的?是TCP还是Http?

        套接字(Socket)是一种网络编程的抽象,提供了一种通用的接口,使得程序能够灵活地使用不同的网络协议进行通信。套接字并不局限于某一种协议,可以基于TCP(SOCK_STREAM)或UDP(SOCK_DGRAM)等多种协议进行操作。HTTP协议是一种应用层协议,通常运行在TCP套接字之上。通过掌握套接字编程,可以实现各种网络应用,从简单的客户端-服务器通信到复杂的分布式系统。

总结

        本文深入探讨了C++网络编程中的套接字(Socket)开发技术,详细讲解了其概念、底层原理、网络协议知识、本质及需要掌握的核心点,并通过经典实例进行解析。我们介绍了同步与异步I/O、多线程与事件驱动模型、高效网络编程的关键技术,最后详细展示了如何使用Boost.Asio实现一个高效的异步HTTP服务器。通过这些技术和示例代码,高级C++开发者可以深入理解和掌握网络编程的关键技术,为开发高效、可扩展的网络应用打下坚实的基础。希望这些代码和注释能够帮助你更好地理解和应用C++网络编程。

http://www.hengruixuexiao.com/news/22753.html

相关文章:

  • 所有网站的名字大全青岛谷歌推广
  • 微网站内容页模板什么是搜索引擎推广
  • 长春网站制作专业百度网址大全旧版本
  • 利用小程序反向做网站舟山seo
  • 国外旅游哪几个网站做攻略好东莞网站优化公司
  • 哪些网站可以赚钱网络营销的方法有哪些?举例说明
  • 武汉做网站互助系统seo优化工具大全
  • 邯郸信息港手机版搜索引擎优化包括哪些内容
  • 如何做网站赚钱最近发生的热点新闻
  • 湘阴县住房建设局网站百度一下搜索
  • 襄阳文明建设投诉网站软文推广公司有哪些
  • 京东网站建设评估推广平台有哪些?
  • html5做静态网站国内新闻最新5条
  • 女生java网站开发培训后好找工作百度站长管理平台
  • microsoft做网站网站策划方案
  • 郑州做网站推友链大全
  • 江苏省华建建设股份有限公司网站软文广告经典案例
  • 苏州外贸网站免费私人网站建设软件
  • 做网站的相关规定怎么营销推广
  • 工业信息部网站备案今日头条新闻10条
  • 网页后端开发需要学什么广州网站优化服务
  • 建设微信商城网站制作免费下载百度到桌面
  • 汕头市研发网站建设新手如何做网上销售
  • 加强政府信息公开和网站建设如何利用网络进行推广和宣传
  • 网络服务提供者不履行法律行政法规规定的哪些行业适合做seo
  • 学编程做网站网络推广工作
  • 刚开始做网站要传数据库吗百度网址大全旧版本
  • 多种专业网站建设公众号推广费用一般多少
  • oa管理系统模板成都百度快照优化排名
  • 律师事务所网站建设如何看待百度竞价排名