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

平邑做网站软件开发用到的软件

平邑做网站,软件开发用到的软件,帝国cms做招聘网站,广东营销型网站建设目录 前言#xff1a; socket是什么 socket基本原理框图 socket基本函数 1 socket() 函数 2 bind()函数 3 connect()函数 4 listen() 函数 5 accept() 函数 6 read() write() send() recv()函数 7 close()函数 8 字节序转换#xff08;hton#xff09; 示例代码 …目录 前言 socket是什么 socket基本原理框图 socket基本函数 1 socket() 函数 2 bind()函数 3 connect()函数 4 listen() 函数 5 accept() 函数 6 read() write() send() recv()函数 7 close()函数 8 字节序转换hton 示例代码 前言 进程间通信IPCInterprocess communication是一组编程接口让程序员能够协调不同的进程使之能在一个操作系统里同时运行并相互传递、交换信息。这使得一个程序能够在同一时间里处理许多用户的要求。因为即使只有一个用户发出要求也可能导致一个操作系统中多个进程的运行进程之间必须互相通话。IPC接口就提供了这种可能性。每个IPC方法均有它自己的优点和局限性一般对于单个程序而言使用所有的IPC方法是不常见的。 进程间通信的8种方法 1、无名管道通信 无名管道 pipe 管道是一种半双工的通信方式数据只能单向流动而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。 2、高级管道通信 高级管道popen将另一个程序当做一个新的进程在当前程序进程中启动则它算是当前程序的子进程这种方式我们成为高级管道方式。 3、有名管道通信 有名管道 named pipe 有名管道也是半双工的通信方式但是它允许无亲缘关系进程间的通信。 4、消息队列通信 消息队列 message queue 消息队列是由消息的链表存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。 5、信号量通信 信号量 semophore 信号量是一个计数器可以用来控制多个进程对共享资源的访问。它常作为一种锁机制防止某进程正在访问共享资源时其他进程也访问该资源。因此主要作为进程间以及同一进程内不同线程之间的同步手段。 6、信号 信号 sinal 信号是一种比较复杂的通信方式用于通知接收进程某个事件已经发生。 7、共享内存通信 共享内存 shared memory 共享内存就是映射一段能被其他进程所访问的内存这段共享内存由一个进程创建但多个进程都可以访问。共享内存是最快的 IPC 方式它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制如信号两配合使用来实现进程间的同步和通信。 8、套接字通信 套接字 socket 套接口也是一种进程间通信机制与其他通信机制不同的是它可用于不同机器间的进程通信。 socket是什么 你也许听很多高手说过UNIX/Linux 中的一切都是文件那个家伙说的没错。 为了表示和区分已经打开的文件UNIX/Linux 会给每个文件分配一个 ID这个 ID 就是一个整数被称为文件描述符File Descriptor。例如 通常用 0 来表示标准输入文件stdin它对应的硬件设备就是键盘通常用 1 来表示标准输出文件stdout它对应的硬件设备就是显示器。 UNIX/Linux 程序在执行任何形式的 I/O 操作时都是在读取或者写入一个文件描述符。一个文件描述符只是一个和打开的文件相关联的整数它的背后可能是一个硬盘上的普通文件、FIFO、管道、终端、键盘、显示器甚至是一个网络连接。 请注意网络连接也是一个文件它也有文件描述符你必须理解这句话。 我们可以通过 socket() 函数来创建一个网络连接或者说打开一个网络文件socket() 的返回值就是文件描述符。有了文件描述符我们就可以使用普通的文件操作函数来传输数据了例如 用 read() 读取从远程计算机传来的数据用 write() 向远程计算机写入数据。你看只要用 socket() 创建了连接剩下的就是文件操作了socket通信原来就是如此简单 socket基本原理框图 1.服务端首先初始化Socket(),然后和接口进行绑定bind()和监听listen(),然后调用accept()进行阻塞。 2.客户端初始化socket(),然后调用connect与服务端进行连接然后客户端负责发送请求服务端接收并且处理请求。write()read().在 UNIX/Linux 系统中为了统一对各种硬件的操作简化接口不同的硬件设备也都被看成一个文件。对这些文件的操作等同于对磁盘上普通文件的操作。 socket基本函数 1 socket() 函数 #include sys/types.h #include sys/socket.h int socket (int af, int type, int protocal ); 1) af 为地址族Address Family也就是 IP 地址类型常用的有 AF_INET 和 AF_INET6。AF 是“Address Family”的简写INET是“Inetnet”的简写。AF_INET 表示 IPv4 地址例如 127.0.0.1AF_INET6 表示 IPv6 地址例如 1030::C9B4:FF12:48AA:1A2B。 大家需要记住127.0.0.1它是一个特殊IP地址表示本机地址。 2) type 为数据传输方式/套接字类型常用的有 SOCK_STREAM流格式套接字/面向连接的套接字 和 SOCK_DGRAM数据报套接字/无连接的套接字 3) protocol 表示传输协议常用的有 IPPROTO_TCP 和 IPPTOTO_UDP分别表示 TCP 传输协议和 UDP 传输协议。 2 bind()函数 socket函数用来创建套接字确定套接字的各种属性然后服务器端要用 bind() 函数将套接字与特定的 IP 地址和端口绑定起来只有这样流经该 IP 地址和端口的数据才能交给套接字处理。类似地客户端也要用 connect() 函数建立连接。 #include sys/types.h #include sys/socket.h int bind (int sockfd, const struct sockaddr* my_addr, socklen_t addlen ); //前边的专用地址的指针强制转换成 struct sockaddr* 就行1sock 为 socket 文件描述符 2addr 为 sockaddr 结构体变量的指针 3addrlen 为 addr 变量的大小可由 sizeof() 计算得出。 下面的代码将创建的套接字与IP地址 127.0.0.1、端口 1234 绑定 //创建套接字int serv_sock socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//创建sockaddr_in结构体变量struct sockaddr_in serv_addr;memset(serv_addr, 0, sizeof(serv_addr)); //每个字节都用0填充serv_addr.sin_family AF_INET; //使用IPv4地址serv_addr.sin_addr.s_addr inet_addr(127.0.0.1); //具体的IP地址serv_addr.sin_port htons(1234); //端口//将套接字和IP、端口绑定bind(serv_sock, (struct sockaddr*)serv_addr, sizeof(serv_addr)); 这里我们使用 sockaddr_in 结构体然后再强制转换为 sockaddr 类型后边会讲解为什么这样做。 sockaddr_in 结构体 接下来不妨先看一下 sockaddr_in 结构体它的成员变量如下 struct sockaddr_in{sa_family_t sin_family; //地址族Address Family也就是地址类型uint16_t sin_port; //16位的端口号struct in_addr sin_addr; //32位IP地址char sin_zero[8]; //不使用一般用0填充}; 1) sin_family 和 socket() 的第一个参数的含义相同取值也要保持一致。 2) sin_prot 为端口号。uint16_t 的长度为两个字节理论上端口号的取值范围为 0~65536但 0~1023 的端口一般由系统分配给特定的服务程序例如 Web 服务的端口号为 80FTP 服务的端口号为 21所以我们的程序要尽量在 1024~65536 之间分配端口号。 端口号需要用 htons() 函数转换后面会讲解为什么。 3) sin_addr 是 struct in_addr 结构体类型的变量下面会详细讲解。 4) sin_zero[8] 是多余的8个字节没有用一般使用 memset() 函数填充为 0。上面的代码中先用 memset() 将结构体的全部字节填充为 0再给前3个成员赋值剩下的 sin_zero 自然就是 0 了。 in_addr 结构体 sockaddr_in 的第3个成员是 in_addr 类型的结构体该结构体只包含一个成员如下所示 struct in_addr{in_addr_t s_addr; //32位的IP地址}; in_addr_t 在头文件 netinet/in.h 中定义等价于 unsigned long长度为4个字节。也就是说s_addr 是一个整数而IP地址是一个字符串所以需要 inet_addr() 函数进行转换例如 unsigned long ip inet_addr(127.0.0.1);printf(%ld\n, ip); 运行结果 16777343 为什么要搞这么复杂结构体中嵌套结构体而不用 sockaddr_in 的一个成员变量来指明IP地址呢socket() 函数的第一个参数已经指明了地址类型为什么在 sockaddr_in 结构体中还要再说明一次呢这不是啰嗦吗 这些繁琐的细节确实给初学者带来了一定的障碍我想这或许是历史原因吧后面的接口总要兼容前面的代码。各位读者一定要有耐心暂时不理解没有关系根据教程中的代码“照猫画虎”即可时间久了自然会接受。 为什么使用 sockaddr_in 而不使用 sockaddr bind() 第二个参数的类型为 sockaddr而代码中却使用 sockaddr_in然后再强制转换为 sockaddr这是为什么呢 sockaddr 结构体的定义如下 struct sockaddr{sa_family_t sin_family; //地址族Address Family也就是地址类型char sa_data[14]; //IP地址和端口号}; 下图是 sockaddr 与 sockaddr_in 的对比括号中的数字表示所占用的字节数 sockaddr 和 sockaddr_in 的长度相同都是16字节只是将IP地址和端口号合并到一起用一个成员 sa_data 表示。要想给 sa_data 赋值必须同时指明IP地址和端口号例如”127.0.0.1:80“遗憾的是没有相关函数将这个字符串转换成需要的形式也就很难给 sockaddr 类型的变量赋值所以使用 sockaddr_in 来代替。这两个结构体的长度相同强制转换类型时不会丢失字节也没有多余的字节。 可以认为sockaddr 是一种通用的结构体可以用来保存多种类型的IP地址和端口号而 sockaddr_in 是专门用来保存 IPv4 地址的结构体。另外还有 sockaddr_in6用来保存 IPv6 地址它的定义如下 struct sockaddr_in6 { sa_family_t sin6_family; //(2)地址类型取值为AF_INET6in_port_t sin6_port; //(2)16位端口号uint32_t sin6_flowinfo; //(4)IPv6流信息struct in6_addr sin6_addr; //(4)具体的IPv6地址uint32_t sin6_scope_id; //(4)接口范围ID}; 正是由于通用结构体 sockaddr 使用不便才针对不同的地址类型定义了不同的结构体。 3 connect()函数 #include sys/types.h #include sys/socket.h int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen ); //成功返回服务端的文件描述符 各个参数的说明和 bind() 相同不再赘述。 4 listen() 函数 #include sys/socket.h int listen( int sockfd, int backlog ); //backlog是指完全连接ESTABLISHED的客户端的上限 对于服务器端程序使用 bind() 绑定套接字后还需要使用 listen() 函数让套接字进入被动监听状态再调用 accept() 函数就可以随时响应客户端的请求了。 sock 为需要进入监听状态的套接字backlog 为请求队列的最大长度。 所谓被动监听是指当没有客户端请求时套接字处于“睡眠”状态只有当接收到客户端请求时套接字才会被“唤醒”来响应请求。 请求队列 当套接字正在处理客户端请求时如果有新的请求进来套接字是没法处理的只能把它放进缓冲区待当前请求处理完毕后再从缓冲区中读取出来处理。如果不断有新的请求进来它们就按照先后顺序在缓冲区中排队直到缓冲区满。这个缓冲区就称为请求队列Request Queue。 缓冲区的长度能存放多少个客户端请求可以通过 listen() 函数的 backlog 参数指定但究竟为多少并没有什么标准可以根据你的需求来定并发量小的话可以是10或者20。 如果将 backlog 的值设置为 SOMAXCONN就由系统来决定请求队列长度这个值一般比较大可能是几百或者更多。 当请求队列满时就不再接收新的请求对于 Linux客户端会收到 ECONNREFUSED 错误对于 Windows客户端会收到 WSAECONNREFUSED 错误。 注意listen() 只是让套接字处于监听状态并没有接收请求。接收请求需要使用 accept() 函数。 5 accept() 函数 #include sys/types.h #include sys/socket.h int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen ); //成功返回客户端的文件描述符 当套接字处于监听状态时可以通过 accept() 函数来接收客户端请求 它的参数与 listen() 和 connect() 是相同的sock 为服务器端套接字addr 为 sockaddr_in 结构体变量addrlen 为参数 addr 的长度可由 sizeof() 求得。 accept() 返回一个新的套接字来和客户端通信addr 保存了客户端的IP地址和端口号而 sock 是服务器端的套接字大家注意区分。后面和客户端通信时要使用这个新生成的套接字而不是原来服务器端的套接字。 最后需要说明的是listen() 只是让套接字进入监听状态并没有真正接收客户端请求listen() 后面的代码会继续执行直到遇到 accept()。accept() 会阻塞程序执行后面代码不能被执行直到有新的请求到来。 6 read() write() send() recv()函数 write() read() 通用读写 ssize_t write(int fd, const void *buf, size_t nbytes); ssize_t read(int fd, void *buf, size_t nbytes); 前面我们说过两台计算机之间的通信相当于两个套接字之间的通信在服务器端用 write() 向套接字写入数据客户端就能收到然后再使用 read() 从套接字中读取出来就完成了一次通信。 除此之外还有其他方法进行读写套接字如下 TCP数据读写 #include sys/types.h #include sys/socket.h ssize_t recv(int sockfd, void *buf, size_t len, int flags ); ssize_t send(int sockfd, void *buf, size_t len, int flags );UDP读写 #include sys/types.h #include sys/socket.h ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addlen); ssize_t sendto(int sockfd, void *buf, size_t len, int flags, struct sockaddr *dest_addr, socklen_t *addlen);socket通用读写 #include sys/socket.h ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags ); ssize_t sendmsg(int sockfd, struct msghdr *msg, int flags ); struct msghdr {void *msg_name; //socket地址socklen_t msg_namelen //socket地址长度struct iovec *msg_iov; //分散的内存块数组int msg_iovlen; //内存块数量void *msg_control; //指向辅助数据的起始位置socklen_t msg_controllen;//辅助数据长度int msg_flags; //复制函数中的flags }; struct iovec {void *iov_base; //内存起始地址size_t iov_len; //这块内存长度 }; 7 close()函数 #include unistd.h int close(int fd); //通用文件描述符关闭将fd的引用计数减一#include sys/socket.h int shutdown(int sockfd, int howto ); //网络专用howto取值SHUT_RD, SHUT_WR, SHUT_RDWR。 8 字节序转换hton #include netinet/in.h unsigned long int htonl(unsigned long int hostlong); unsigned short int htons(unsigned short int hostshort); unsigned long int ntohl(unsigned long int netlong); unsigned short int ntohs(unsigned short int netshort); htons是将整型变量从主机字节顺序转变成网络字节顺序 就是整数在地址空间存储方式变为高位字节存放在内存的低地址处。 网络字节顺序是TCP/IP中规定好的一种数据表示格式它与具体的CPU类型、操作系统等无关从而可以保证数据在不同主机之间传输时能够被正确解释网络字节顺序采用big-endian排序方式。htons的功能将一个无符号短整型的主机数值转换为网络字节顺序即大尾顺序(big-endian) htonl,其实是host to network, l 的意思是返回类型是long. 将主机数转换成无符号长整型的网络字节顺序。本函数将一个32位数从主机字节顺序转换成网络字节顺序。 示例代码 本示例是本地多进程间进行通信完成进程1和进程2分别和service进程建立socket进而使本地进程1和进程2进行通信 client1 代码 /************************************************************************* file Name: client.c author: C G mail: - created Time: 2023年03月01日 星期三 18时19分46秒 version: 1.0************************************************************************/ #includestdio.h #includesys/types.h #includesys/socket.h #includenetinet/in.h #includearpa/inet.h #includesys/time.h #includesys/ioctl.h #includeunistd.h #includestdlib.h #includesys/time.h #includestring.h #include../common.hint init(void) {int len 0;int clientSockfd 0;int clientLen 0;int result 0;struct sockaddr_in clientAddress;struct sockaddr_in serverAddress;clientSockfd socket(AF_INET, SOCK_STREAM, 0);memset(serverAddress, 0x00, sizeof(serverAddress));serverAddress.sin_family AF_INET;serverAddress.sin_addr.s_addr inet_addr(SERVICE_STRING_IP);serverAddress.sin_port htons(SERVICE_PORT);len sizeof(serverAddress);memset(clientAddress, 0x00, sizeof(clientAddress));clientAddress.sin_family AF_INET;clientAddress.sin_addr.s_addr htonl(INADDR_ANY);clientAddress.sin_port htons(BT_PORT_ID);clientLen sizeof(clientAddress);bind(clientSockfd, (struct sockaddr*)clientAddress, clientLen);result connect(clientSockfd, (struct sockaddr *)serverAddress, len);if(result -1){printf(connect result is error\n);exit(1);}return clientSockfd; }int main() {int clientSockfd 0;struct Data myData;struct timeval start;struct timeval end;clientSockfd init();printf(i am is BT\n);memset(myData, 0x00, sizeof(myData));myData.src BT_PORT_ID;myData.der HMI_PORT_ID;myData.evt 1;write(clientSockfd, myData, sizeof(myData));gettimeofday(start,NULL);printf(BT write time is %ld.%06ld\n,start.tv_sec, start.tv_usec);printf(BT write src %d , der %d , evt %d \n,myData.src, myData.der, myData.evt);memset(myData, 0x00, sizeof(myData));read(clientSockfd, myData, sizeof(myData));gettimeofday(end,NULL);printf(BT read time is %ld.%06ld\n,end.tv_sec, end.tv_usec);printf(BT read src %d , der %d , evt %d \n,myData.src, myData.der, myData.evt);close(clientSockfd);return 0; }client 2 代码 /************************************************************************* file Name: client.c author: C G mail: - created Time: 2023年03月01日 星期三 18时19分46秒 version: 1.0************************************************************************/ #includestdio.h #includesys/types.h #includesys/socket.h #includenetinet/in.h #includearpa/inet.h #includesys/time.h #includesys/ioctl.h #includeunistd.h #includestdlib.h #includesys/time.h #includestring.h #include../common.hint init(void) {int len 0;int clientSockfd 0;int clientLen 0;int result 0;struct sockaddr_in clientAddress;struct sockaddr_in serverAddress;clientSockfd socket(AF_INET, SOCK_STREAM, 0);memset(serverAddress, 0x00, sizeof(serverAddress));serverAddress.sin_family AF_INET;serverAddress.sin_addr.s_addr inet_addr(SERVICE_STRING_IP);serverAddress.sin_port htons(SERVICE_PORT);len sizeof(serverAddress);memset(clientAddress, 0x00, sizeof(clientAddress));clientAddress.sin_family AF_INET;clientAddress.sin_addr.s_addr htonl(INADDR_ANY);clientAddress.sin_port htons(HMI_PORT_ID);clientLen sizeof(clientAddress);bind(clientSockfd, (struct sockaddr*)clientAddress, clientLen);result connect(clientSockfd, (struct sockaddr *)serverAddress, len);if(result -1){printf(connect result is error\n);exit(1);}return clientSockfd; }int main() {int clientSockfd 0;struct Data myData;struct timeval start;struct timeval end;clientSockfd init();printf(i am HMI\n);memset(myData, 0x00, sizeof(myData));read(clientSockfd, myData, sizeof(myData));gettimeofday(end,NULL);printf(HMI read time is %ld.%06ld\n,end.tv_sec, end.tv_usec);printf(HMI read src %d , der %d , evt %d \n,myData.src, myData.der, myData.evt);memset(myData, 0x00, sizeof(myData));myData.src HMI_PORT_ID;myData.der BT_PORT_ID;myData.evt 2;write(clientSockfd, myData, sizeof(myData));gettimeofday(start,NULL);printf(HMI write time is %ld.%06ld\n,start.tv_sec, start.tv_usec);printf(HMI write src %d , der %d , evt %d \n,myData.src, myData.der, myData.evt);close(clientSockfd);return 0;}service 代码 /************************************************************************* file Name: service.c author: C G mail: - created Time: 2023年03月01日 星期三 18时15分49秒 version: 1.0************************************************************************/extern C { #includestdio.h #includesys/types.h #includesys/socket.h #includenetinet/in.h #includesys/time.h #includesys/ioctl.h #includeunistd.h #includestdlib.h #includestring.h#include../common.h }#includemapint main() {std::mapint, int myMap;int server_sockfd,client_sockfd;unsigned int server_len, client_len;struct sockaddr_in server_address;struct sockaddr_in client_address;int result;fd_set readfds, testfds;struct Data myData;memset(myData, 0x00, sizeof(myData));server_sockfd socket(AF_INET, SOCK_STREAM, 0);server_address.sin_family AF_INET;server_address.sin_addr.s_addr htonl(INADDR_ANY);server_address.sin_port htons(SERVICE_PORT);server_len sizeof(server_address);bind(server_sockfd, (struct sockaddr*)server_address, server_len);listen(server_sockfd, LISTEN_MAX);FD_ZERO(readfds);FD_SET(server_sockfd,readfds);while(1){char ch;int fd;int nread;ssize_t readSize 0;FD_ZERO(testfds);testfds readfds;result select(FD_SETSIZE, testfds, (fd_set*)0, (fd_set*)0, NULL);if(result 1){printf(is error\n);exit(1);}for(fd 0; fd FD_SETSIZE; fd){if(FD_ISSET(fd, testfds)){if(fd server_sockfd){client_len sizeof(client_address);client_sockfd accept(server_sockfd, (struct sockaddr*)client_address, client_len);FD_SET(client_sockfd, readfds);printf(adding client on fd %d port %d ID:%s\n, client_sockfd, ntohs(client_address.sin_port), HMI_PORT_IDntohs(client_address.sin_port)?HMI_PORT_ID:BT_PORT_IDntohs(client_address.sin_port)?BT_PORT_ID:other_port_ID);myMap[ntohs(client_address.sin_port)] client_sockfd;}else{readSize read(fd, myData, sizeof(myData));if(readSize 0){struct timeval start;gettimeofday(start,NULL);printf(read time is %ld.%06ld\n,start.tv_sec, start.tv_usec);printf(read client on fd %d ID %s,src %d , der %d %d, evn %d \n,fd,HMI_PORT_IDmyData.der?HMI_PORT_ID:BT_PORT_IDntohs(client_address.sin_port)?BT_PORT_ID:other_port_ID,myData.src, myData.der, myMap[myData.der],myData.evt);write(myMap[myData.der], myData, sizeof(myData));printf(write client on fd %d ID %s,src %d , der %d %d, evn %d \n\n,fd,HMI_PORT_IDmyData.der?HMI_PORT_ID:BT_PORT_IDntohs(client_address.sin_port)?BT_PORT_ID:other_port_ID,myData.src, myData.der, myMap[myData.der],myData.evt);}else{FD_CLR(fd, readfds);printf(removing client on fd %d\n,fd);std::mapint,int::iterator key myMap.find(fd);if(key ! myMap.end()){myMap.erase(key);}nread;write(fd, nread, 1);}}}}}return 0; }
http://www.w-s-a.com/news/859575/

相关文章:

  • 网站软件免费下载安装泰安网站建设收费标准
  • 部署iis网站校园网站设计毕业设计
  • 网站快慢由什么决定塘沽手机网站建设
  • 苏州那家公司做网站比较好装修队做网站
  • 外贸网站推广中山网站流量团队
  • 网站前端设计培训做一份网站的步zou
  • 网站备案拍照茶叶网页设计素材
  • wordpress 手机商城模板关键词优化软件有哪些
  • 网站301做排名python做的网站如何部署
  • 昆山做企业网站工信部网站 备案
  • 做英文的小说网站有哪些网站做qq登录
  • 湖州建设局招投标网站深圳广告公司集中在哪里
  • 重庆主城推广网站建设商城网站建设预算
  • 宁波品牌网站推广优化公司开发公司工程部工作总结
  • 长沙建站模板微信网站建设方案
  • 不让网站在手机怎么做门户网站 模板之家
  • 网站建设及推广图片wordpress文章摘要调用
  • 手机版网站案例全国信息企业公示系统
  • 模仿别人网站建设银行广州招聘网站
  • 沧州网站建设沧州内页优化
  • 代加工网站有哪些专门做网站关键词排名
  • 郑州做景区网站建设公司软件开发者模式怎么打开
  • 长沙企业网站建设哪家好做app一般多少钱
  • 南宁一站网网络技术有限公司网站开发技术应用领域
  • 公司网站建设方案ppt专业构建网站的公司
  • 深圳网站建设方维网络网站框架设计好后怎么做
  • 合肥网站建设过程网站栏目建设调研
  • 手机访问网站页面丢失北京电商平台网站建设
  • 郑州网站怎么推广中山 网站关键词优化
  • 国外试用网站空间网站建设与管理题目