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

寮步镇网站建设公司做个企业网站多少钱

寮步镇网站建设公司,做个企业网站多少钱,北京app开发公司排名,网站推广排名有什么技巧一.理解TCP和UDP TCP#xff08;Transmission Control Protocol#xff09;和UDP#xff08;User Datagram Protocol#xff09;是两种常见的传输层协议#xff0c;用于在计算机网络中提供可靠的数据传输。 1.TCP#xff1a; 连接导向#xff1a;TCP是一种面向连接的…一.理解TCP和UDP TCPTransmission Control Protocol和UDPUser Datagram Protocol是两种常见的传输层协议用于在计算机网络中提供可靠的数据传输。 1.TCP 连接导向TCP是一种面向连接的协议通信双方在数据传输前需要先建立可靠的连接。可靠性TCP提供可靠的数据传输通过使用序列号、确认应答、超时重传等机制来确保数据的完整性和可靠性。流量控制与拥塞控制TCP通过流量控制和拥塞控制来调节发送端的数据发送速率以避免网络拥堵或丢包现象。有序性TCP保证数据按照发送顺序到达目标端不会发生乱序问题。面向字节流TCP将数据视为连续的字节流进行传输没有消息边界的概念。 TCP适用于对数据完整性和可靠性要求较高的应用场景如文件传输、电子邮件、网页浏览等。 2.UDP 无连接UDP是一种无连接的协议通信双方在数据传输时不需要先建立连接。不可靠性相比TCPUDP不提供数据的可靠性保证数据可能会丢失、乱序或重复。无拥塞控制UDP不对数据发送速率进行调节因此可能会造成网络拥堵和丢包现象。无序性UDP没有保证数据按照发送顺序到达目标端的机制数据可能会乱序到达。面向报文UDP将数据视为独立的报文进行传输保留了消息的边界。 UDP适用于对实时性要求较高、数据丢失可容忍或应用自身提供可靠性机制的应用场景如音频/视频流传输、在线游戏等。 需要根据具体应用需求选择使用TCP还是UDP。TCP提供可靠的有序数据传输适合对数据完整性要求较高的场景而UDP提供了更低的延迟和更高的实时性适用于对实时性要求较高、数据丢失可容忍的场景。 TCP/IP协议栈 二.实现基于TCP的服务器端/客户端 1.TCP服务器端的默认函数调用顺序 2.TCP客户端的默认函数调用顺序 3.基于TCP的服务器端/客户端函数调用关系 4.实现迭代回声服务器端/客户端 VM ubuntu编译Cppg -stdc11  文件名 -o  生成文件名 1echo_server.cpp g -stdc11 echo_server.cpp -o eserver./eserver 9190 #include iostream #include cstring #include unistd.h #include arpa/inet.h #include sys/socket.h#define BUF_SIZE 1024void error_handling(const char *message);int main(int argc, char *argv[]) {int serv_sock, clnt_sock;char message[BUF_SIZE];int str_len, i;struct sockaddr_in serv_adr, clnt_adr;socklen_t clnt_adr_sz;if (argc ! 2) {std::cout Usage: argv[0] port std::endl;exit(1);}serv_sock socket(PF_INET, SOCK_STREAM, 0);if (serv_sock -1)error_handling(socket() error);memset(serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family AF_INET;serv_adr.sin_addr.s_addr htonl(INADDR_ANY);serv_adr.sin_port htons(atoi(argv[1]));if (bind(serv_sock, (struct sockaddr*)serv_adr, sizeof(serv_adr)) -1)error_handling(bind() error);if (listen(serv_sock, 5) -1)error_handling(listen() error);clnt_adr_sz sizeof(clnt_adr);for (i 0; i 5; i) {clnt_sock accept(serv_sock, (struct sockaddr*)clnt_adr, clnt_adr_sz);if (clnt_sock -1)error_handling(accept() error);elsestd::cout Connected client i1 std::endl;while ((str_len read(clnt_sock, message, BUF_SIZE)) ! 0)write(clnt_sock, message, str_len);close(clnt_sock);}close(serv_sock);return 0; }void error_handling(const char *message) {std::cout message std::endl;exit(1); }2echo_client.cpp g -stdc11 echo_client.cpp -o eclient./eclient 127.0.0.1 9190 #include iostream #include cstring #include unistd.h #include arpa/inet.h #include sys/socket.h#define BUF_SIZE 1024void error_handling(const char *message);int main(int argc, char *argv[]) {int sock;char message[BUF_SIZE];int str_len;struct sockaddr_in serv_adr;if (argc ! 3) {std::cout Usage: argv[0] IP port std::endl;exit(1);}sock socket(PF_INET, SOCK_STREAM, 0);if (sock -1)error_handling(socket() error);memset(serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family AF_INET;serv_adr.sin_addr.s_addr inet_addr(argv[1]);serv_adr.sin_port htons(atoi(argv[2]));if (connect(sock, (struct sockaddr*)serv_adr, sizeof(serv_adr)) -1)//调用conndect函数error_handling(connect() error!);elsestd::cout connected........... std::endl;while (true) {std::cout Input message (Q to quit): ;std::cin.getline(message, BUF_SIZE);if (strcmp(message, q) 0 || strcmp(message, Q) 0)break;write(sock, message, strlen(message));str_len read(sock, message, BUF_SIZE-1);message[str_len] \0;std::cout Message from server: message std::endl;}close(sock);//调用close函数向相应套接字发送EOFEOF意味着中断连接return 0; }void error_handling(const char *message) {std::cerr message std::endl;exit(1); }存在问题 如果数据量太大操作系统可能把数据分成多个数据包发送到客户端但是服务器端每次接收读取之后只调用一次 write 函数。另外客户端有可能在尚未收到全部数据包时就调用 read函数导致回声不完整。 三.总结一 1.说明TCP/IP的4层协议栈并说明TCP和UDP套接字经过的层级结构差异。 TCP/IP协议栈是一个网络通信的基本模型它由四层协议组成分别是应用层、传输层、网络层和链路层。 应用层应用层提供了用户与网络之间的接口负责处理特定的应用程序数据。常见的应用层协议有HTTP、FTP、SMTP等。 传输层传输层主要负责在网络中传输数据。其中最重要的两个协议是TCP传输控制协议和UDP用户数据报协议。 TCP套接字经过传输层。TCP是一种面向连接的协议提供可靠的数据传输。它通过建立连接、数据分段、流量控制、拥塞控制等机制来保证数据的可靠性和顺序性。TCP套接字在传输层使用IP地址和端口号进行标识。 UDP套接字也经过传输层。UDP是一种无连接的协议不提供可靠性保证。它将数据打包成数据报发送不关心数据是否能够到达目标地址。UDP套接字同样使用IP地址和端口号进行标识。 网络层IP层网络层负责将数据从源主机传输到目标主机它使用IP协议进行数据包的路由选择和转发。IP协议为数据包分配唯一的IP地址。 链路层链路层是网络通信的物理层和数据链路层接口负责将网络层传输的数据转换成比特流进行物理传输。它包括了物理寻址、帧封装和错误检测等功能。 IP层和链路层之间的关系是协同工作。IP层将数据封装成IP数据包在传输过程中会添加源IP地址和目标IP地址然后将数据包交给链路层进行物理传输。链路层收到IP数据包后会添加自己的帧头和帧尾信息并将数据包转换成比特流发送。接收端的链路层会将接收到的比特流重新组装成帧并去除链路层的头部和尾部信息然后将数据包交给IP层进行进一步处理。总结来说IP层负责寻址、路由选择和数据包的传输控制而链路层负责物理传输和错误检测。它们共同协作完成了数据从源主机到目标主机的传输过程。 所以TCP和UDP套接字在协议栈的层级结构上并无差异都经过传输层。它们的主要区别在于TCP提供面向连接的可靠传输而UDP提供无连接的不可靠传输。根据应用场景的需要可以选择使用TCP或UDP来进行数据传输。 2.为什么要把TCP/IP协议栈分成4层或7层结合开放式系统回答? TCP/IP协议栈被分成多层的设计是出于以下几个原因其中也与开放式系统相关 模块化设计将TCP/IP协议栈分成多层可以实现模块化的设计每一层都有明确定义的功能和责任。这样可以提高系统的可维护性和可扩展性。如果需要对某一层进行修改或替换只需关注特定层而无需改动其他层。 逻辑分离将网络通信过程划分为不同的层级可以实现逻辑上的分离。每一层专注于自身的任务不需要关心其他层的具体实现。这种分离使得各层之间的接口定义清晰降低了系统的复杂性。 标准化和互操作性将TCP/IP协议栈分成多层使得每一层的功能和协议得到标准化。这样不同厂商、不同操作系统的设备都可以按照相同的标准实现对应的层从而实现互操作性。这种开放式的设计使得不同设备和系统能够无缝地进行通信。 灵活性和可定制性通过分层设计可以根据具体需求选择性地使用不同层提供的功能。例如某些应用场景可能只需要传输层和网络层的功能可以选择性地使用这些层而不需要实现其他层。这种灵活性和可定制性使得TCP/IP协议栈适应各种不同的网络和应用需求。 综上所述将TCP/IP协议栈分成多层结构是为了实现模块化设计、逻辑分离、标准化和互操作性以及提供灵活性和可定制性。这样的设计使得开放式系统中的不同设备和系统能够相互通信并且能够根据具体需求进行定制和扩展。 3.客户端调用connect函数向服务器端发送连接请求。服务器端调用哪个函数后客户端可以调用connect函数 服务器端调用 listen 函数后客户端可以调用 connect 函数。 在TCP通信中服务器端需要先调用listen函数来监听指定的端口以便接受客户端的连接请求。listen函数使得服务器端处于监听状态等待客户端连接。一旦服务器端调用了listen函数客户端就可以通过调用connect函数向服务器端发送连接请求。connect函数会建立与服务器端的连接并进行三次握手来确保连接的可靠性。 所以客户端需要在服务器端调用listen函数之后才能调用connect函数以发起与服务器的连接。 4.什么时候创建连接请求等待队列有何作用和accept有什么关系 连接请求等待队列是在服务器端调用listen函数后创建的。它的作用是用于存储尚未被服务器端accept函数接受的客户端连接请求。 当服务器端调用listen函数后它会开始监听指定的端口并将该端口设置为监听状态等待客户端的连接请求。如果有多个客户端同时向服务器端发送连接请求而服务器端只能逐个处理这些请求这时就需要使用连接请求等待队列。 连接请求等待队列允许服务器端在处理一个连接请求时将其他连接请求暂时保存起来以便后续处理。通过使用连接请求等待队列可以确保当服务器端正在处理一个连接请求时其他连接请求不会被丢失。 当服务器端调用accept函数时它从连接请求等待队列中取出一个连接请求进行处理。accept函数会建立与客户端的连接并返回一个新的套接字服务器端可通过这个套接字与对应的客户端进行通信。 因此连接请求等待队列与accept函数密切相关。连接请求等待队列存储了尚未被接受的客户端连接请求而accept函数则负责从队列中取出连接请求并建立连接。通过连接请求等待队列和accept函数的配合使用服务器端能够管理和处理多个客户端的连接请求。 5.客户端中为何不需要调用bind函数分配函数地址如果不调用bin函数那么何时如何向套接字分配IP地址和端口号 在客户端中不需要调用bind()函数来分配函数地址是因为客户端一般不需要绑定特定的IP地址和端口号。客户端的套接字可以通过操作系统自动分配可用的临时端口并自动关联客户端的IP地址。 当客户端创建套接字时操作系统会自动选择一个可用的本地端口并将其与套接字进行关联。这个过程通常称为隐式绑定implicit binding。 隐式绑定可以确保客户端使用的本地端口是唯一的并且不会与其他应用程序冲突。对于大多数客户端应用程序而言这种自动分配是足够的无需显式调用bind()函数。 需要注意的是如果你想要在客户端使用特定的本地IP地址和端口号或者需要进行端口重用等特殊操作那么你可能需要调用bind()函数来手动指定这些参数。但一般情况下客户端并不需要手动调用bind()函数来分配函数地址。 四.回声客户端的功能实现加减乘----应用层协议设计 要求服务器端从客户端获得多个数字和运算符信息然后把结果传回客户端。 1.op_server.cpp #includeiostream #includecstring #includeunistd.h #includearpa/inet.h #includesys/socket.h#define BUF_SIZE 1024 #define OPSZ 4void error_handling(const char *message); int calculate(int opnum,int opnds[],char oprator);int main(int argc,char *argv[]){int serv_sock,clnt_sock;char opinfo[BUF_SIZE];int result,opnd_cnt,i;int recv_cnt,recv_len;struct sockaddr_in serv_adr,clnt_adr;socklen_t clnt_adr_sz;if(argc!2){std::coutUsage :argv[0]portstd::endl;exit(1);}serv_socksocket(PF_INET,SOCK_STREAM,0);if(serv_sock-1)error_handling(socket() error);memset(serv_adr,0,sizeof(serv_adr));serv_adr.sin_familyAF_INET;serv_adr.sin_addr.s_addrhtonl(INADDR_ANY);serv_adr.sin_porthtons(atoi(argv[1]));if(bind(serv_sock,(struct sockaddr*)serv_adr,sizeof(serv_adr))-1)error_handling(bind() error);if(listen(serv_sock,5)-1)error_handling(listen() error);clnt_adr_szsizeof(clnt_adr);for(i0;i5;i){opnd_cnt0;//运算个数clnt_sockaccept(serv_sock,(struct sockaddr*)clnt_adr,clnt_adr_sz);read(clnt_sock,opnd_cnt,1);recv_len0;while((opnd_cnt*OPSZ1)recv_len){//读取运算值recv_cntread(clnt_sock,opinfo[recv_len],BUF_SIZE-1);recv_lenrecv_cnt;}resultcalculate(opnd_cnt,(int*)opinfo,opinfo[recv_len-1]);write(clnt_sock,(char*)result,sizeof(result));close(clnt_sock);//当前客户端结束后关闭}close(serv_sock);return 0; }int calculate(int opnum,int opnds[],char op){//功能函数int resultopnds[0],i;switch(op){case :for(i1;iopnum;i) resultopnds[i];break;case -:for(i1;iopnum;i) result-opnds[i];break;case *:for(i1;iopnum;i) result*opnds[i];break;}return result; }void error_handling(const char*message){std::coutmessagestd::endl;exit(1); }2.op_client.cpp #includeiostream #includecstring #includeunistd.h #includearpa/inet.h #includesys/socket.h#define BUF_SIZE 1024 #define RLT_SIZE 4 #define OPSZ 4void error_handling(const char *message);int main(int argc,char *argv[]){int sock;char opmsg[BUF_SIZE];int result,opnd_cnt,i;struct sockaddr_in serv_adr;if(argc!3){std::coutUsage:argv[0]IP portstd::endl;exit(1);}socksocket(PF_INET,SOCK_STREAM,0);if(sock-1)error_handling(socket() error);memset(serv_adr,0,sizeof(serv_adr));serv_adr.sin_familyAF_INET;serv_adr.sin_addr.s_addrinet_addr(argv[1]);serv_adr.sin_porthtons(atoi(argv[2]));if(connect(sock,(struct sockaddr*)serv_adr,sizeof(serv_adr))-1)error_handling(connect() error);elsestd::coutconnect ......std::endl;std::coutOperand count: ;std::cinopnd_cnt;//获取运算个数opmsg[0](char)opnd_cnt;for(i0;iopnd_cnt;i){std::coutOperand i1: ;std::cin*(int*)opmsg[i*OPSZ1];std::cin.ignore();//相当于换行}std::coutOpreator: ;std::cinopmsg[opnd_cnt*OPSZ1];//输入运算符write(sock,opmsg,opnd_cnt*OPSZ2);//传输给服务器端read(sock,result,RLT_SIZE);std::coutOperation result: resultstd::endl;close(sock);return 0; }void error_handling(const char *message){std::coutmessagestd::endl;exit(1); } 五.TCP原理 一TCP套接字中的 I/O 缓冲 TCP套接字的数据收发无边界。为什么这么说呢因为 write() 函数调用后并非立即传输数据read() 函数调用后也并非马上接收数据。如下图所示 缓冲特性 I/O 缓冲在每个TCP套接字中单独存在I/O 缓冲在创建套接字时自动生成即使关闭套接字也会继续传递输出缓冲中遗留的数据关闭套接字将丢失输入缓冲中的数据 注意TCP有流量控制机制所以不存在缓冲溢出 二TCP内部工作原理套接字创建到关闭 1.与对方套接字的连接三次握手 套接字是全双工Full-duplex方式工作的也就是可以双向地传递数据。因此收发数据之前需要做一些准备。 第一次握手服务端知道客户端发送能力没问题第二次握手客户端知道服务端的接收和发送能力没问题第三次握手服务端知道客户端的接收能力没问题 2.与对方主机的数据交换 通过三次握手过程完成了数据交换准备下面开始正式收发数据。 在数据包消失情况中过了一段时间后主机A没有收到对于SEQ1301的ACK确认因此在启动计时器等待ACK应答若相应计时器发生超时Time-out则重传。 3.断开与套接字的连接四次挥手 TCP套接字结束的过程也非常优雅。如果对方还有数据需要传输直接打断连接会出问题。所以断开连接需要双方协商。 数据包内的 FIN 表示断开连接。也就是说双方各发送一次 FIN 消息后断开连接。此过程经历四个阶段。图中主机B向主机A发送了两次ACK501其实第二次 FIN 数据包中的 ACK5001 只是因为收到主机A的ACK消息后未接收数据而重传的。 六.总结二 1.请说明TCP套接字连接设置的三次握手过程。尤其是3次数据交换过程中每次收发的数据内容。 TCP套接字连接的三次握手过程如下 第一次握手 客户端向服务器发送一个SYN同步报文其中包含一个随机生成的初始序列号ISN。这个SYN报文的目的是告诉服务器客户端希望建立连接并且客户端的初始序列号是多少。 第二次握手 服务器收到客户端的SYN报文后会发送一个SYN-ACK同步-确认报文给客户端。这个SYN-ACK报文中服务器会确认收到了客户端的连接请求并且也会生成一个自己的初始序列号ISN。同时服务器也会将自己期望接收到的下一个序列号Next Sequence Number设置为客户端的初始序列号加一。 第三次握手 客户端收到服务器的SYN-ACK报文后会发送一个ACK确认报文给服务器。这个ACK报文中客户端会确认收到了服务器的确认并且会将自己期望接收到的下一个序列号设置为服务器的初始序列号加一。 在这个三次握手的过程中每次收发的数据内容如下 第一次握手 客户端发送的数据内容是一个SYN报文其中包含客户端的初始序列号ISN。 第二次握手 服务器发送的数据内容是一个SYN-ACK报文其中包含服务器的初始序列号ISN和期望接收到的下一个序列号Next Sequence Number。 第三次握手 客户端发送的数据内容是一个ACK报文其中确认了服务器的确认并且设置了客户端期望接收到的下一个序列号。 2.TCP是可靠的数据传输协议但是通过网络通信的过程中可能会丢失数据。请通过ACK和SEQ说明TCP通过何种机制保证丢失数据的可靠传输。 SEQ顺序标识符是给信息编号。ACK是用于回复带有编号的信息。也就是说每次传输信息时都同时发送SEQ标识而受到信息的主机应以SEQ信息为基础回复发送信息的主机。通过这种机制传输数据的主机就可以确认数据是否被正确接收。在传输失败时可以重新传送。 3.TCP套接字中调用write和read函数时数据如何移动结合I/O缓冲进行说明。 当write函数被调用时数据就会向端口的输出缓冲区移动。然后经过网络传输传输到对方主机套接字的输入缓冲。这样输入缓冲中存储的数据通过read函数的响应来读取。 ​​​​​​​​​​​​​​ ​​​​​​​4.对方主机的输入缓冲剩余50字节空间时若本方主机通过write函数请求传输70字节请问TCP如何处理这种情况 对方主机会把输入缓冲中可存储的数据大小传送给要传输数据的数据本方。因此在剩余空间为50字节的情况即使要求传送70字节的数据也不能传输50字节以上剩余的部分保存在传输方的输出缓冲中等待对方主机的输入缓冲出现空间。而且这种交换缓冲多余空间信息的协议被称为滑动窗口协议。 5.创建收发文件的服务器端/客户端。 客户端接收用户输入的传输文件名客户端请求服务器端传输该文件名所指文件如果文件存在服务器端九江其发给客户端反之则断开连接。 file_server.cpp #include iostream #include cstring #include unistd.h #include arpa/inet.h #include sys/socket.h#define BUF_SIZE 30void error_handling(const char *message);int main(int argc, char *argv[]) {int serv_sd, clnt_sd;FILE *fp;char buf[BUF_SIZE];char file_name[BUF_SIZE];int read_cnt;struct sockaddr_in serv_adr, clnt_adr;socklen_t clnt_adr_sz;if (argc ! 2) {std::cout Usage: argv[0] port std::endl;exit(1);}serv_sd socket(PF_INET, SOCK_STREAM, 0);memset(serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family AF_INET;serv_adr.sin_addr.s_addr htonl(INADDR_ANY);serv_adr.sin_port htons(atoi(argv[1]));bind(serv_sd, (struct sockaddr *) serv_adr, sizeof(serv_adr));listen(serv_sd, 5);clnt_adr_sz sizeof(clnt_adr);clnt_sd accept(serv_sd, (struct sockaddr *) clnt_adr, clnt_adr_sz);read(clnt_sd, file_name, BUF_SIZE);fp fopen(file_name, rb);if (fp ! NULL) {while (1) {read_cnt fread((void *) buf, 1, BUF_SIZE, fp);if (read_cnt BUF_SIZE) {write(clnt_sd, buf, read_cnt);break;}write(clnt_sd, buf, BUF_SIZE);}}fclose(fp);close(clnt_sd);close(serv_sd);return 0; }void error_handling(const char *message) {std::cerr message std::endl;exit(1); }file_client.cpp #include iostream #include cstring #include unistd.h #include arpa/inet.h #include sys/socket.h#define BUF_SIZE 30void error_handling(const char *message);int main(int argc, char *argv[]) {int sd;FILE *fp;char buf[BUF_SIZE];char file_name[BUF_SIZE];int read_cnt;struct sockaddr_in serv_adr;if (argc ! 3) {std::cout Usage: argv[0] IP port std::endl;exit(1);}std::cout Input file name: ;std::cin file_name;fp fopen(file_name, wb);sd socket(PF_INET, SOCK_STREAM, 0);memset(serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family AF_INET;serv_adr.sin_addr.s_addr inet_addr(argv[1]);serv_adr.sin_port htons(atoi(argv[2]));connect(sd, (struct sockaddr *) serv_adr, sizeof(serv_adr));write(sd, file_name, strlen(file_name) 1);while ((read_cnt read(sd, buf, BUF_SIZE)) ! 0)fwrite((void *) buf, 1, read_cnt, fp);fclose(fp);close(sd);return 0; }void error_handling(const char *message) {std::cerr message std::endl;exit(1); }问题无法真正的传输文件数据。
http://www.zqtcl.cn/news/369115/

相关文章:

  • 百川网站石家庄物流网站建设
  • 广州外贸网站设计外贸seo外贸推广外贸网站建设外贸网站建设
  • 网站 栏目建设银行网站用户名是什么
  • 服装类的网站建设中原免费网站建设
  • 网站开发培训班多少报名费安徽省建设工程信息网站
  • 旅游网站规划设计余姚网站公司
  • 广州市地铁站地图dede增加手机网站
  • dede 网站名称 空的网站开发行业新闻
  • 网站开发费用做账升级系统
  • 外贸公司网站制作价格网络公司的经营范围有哪些
  • 东莞三合一网站制作海南省生态文明村建设促进会网站
  • 邯郸做企业网站设计的公司福田祥菱m2
  • 手表拍卖网站动漫做暧视频网站
  • 福州网站定制公司如何做p2p网站
  • 微信外链网站开发嘉兴市城市建设门户网站
  • 在手机上如何制作网站qq注册网页入口
  • asp.net程序做的网站安全吗国内什么网站用asp.net
  • 凡科网做网站网站编辑知识
  • c#做交易网站taxonomy wordpress
  • 统一门户网站开发员给我用织梦做的网站
  • 网站上有声的文章是怎么做的深圳市住房和建设局网站和市住宅租赁管理服务中心
  • 如何对网站进行爬虫页面设计存在的问题
  • 知名网站建设加盟合作企业邮箱如何登录
  • asp net mvc做网站软文推广是什么
  • 张家口住房和城乡建设厅网站如何做点击赚钱的网站
  • 网站在建设中无法访问贵州碧江区住房和城乡建设局网站
  • 营销类网站 英文东莞正规的免费网站优化
  • 柳州网站推广最好的公司百度seo优化培训
  • 哈尔滨门户网站建站哪个网站做农产品
  • 网站行业关键词如何建设网站