做画册的网站,西宁网站建设优化案例,免费网页游戏助手,wordpress5.2发布引言#xff1a;网络数据能够正常到达用户并且被接收是进行网络传输的根本目的#xff0c;网络传输的数据发送和接收有多种方案#xff0c;本文章就对通过向量接收和发送等数据传输方式#xff0c;并且对多种I/O模型进详细分析介绍。 目录 一.I/O函数 
1.1 recv和send 
rec… 引言网络数据能够正常到达用户并且被接收是进行网络传输的根本目的网络传输的数据发送和接收有多种方案本文章就对通过向量接收和发送等数据传输方式并且对多种I/O模型进详细分析介绍。 目录 一.I/O函数 
1.1 recv和send 
recv函数 
send函数 
1.2 readv和writev函数 
readv函数 
writev函数 
1.3 recvmsg和recvmsg函数  
recvmsg函数 
sendmsg函数 
1.4 客户—服务器实例 
服务器端代码 
客户端代码 
二.I/O模型介绍 
2.1 阻塞I/OBlocking I/O 
2.2非阻塞I/ONon-blocking I/O 
2.3I/O多路复用I/O Multiplexing 
2.4信号驱动I/OSignal-driven I/O 
2.5异步I/OAsynchronous I/O 
三.监视函数  
3.1select和pselect 
select函数 
pselect函数 
3.2poll函数和ppoll函数 
poll函数 
ppoll函数 
四.总结 一.I/O函数 
1.1 recv和send 
在网络编程中recv 和 send 函数是用于在套接字上进行数据传输的两个基本函数。它们是在Unix-like系统中的Berkeley套接字 API也称为BSD套接字API的一部分在Windows系统中也有对应的实现。 
recv函数 
recv 函数用于从连接的套接字接收数据。函数原型如下 
ssize_t recv(int sockfd, void *buf, size_t len, int flags);sockfd指定接收数据的套接字文件描述符。  buf指向缓冲区的指针用于存放接收到的数据。  len指定缓冲区的大小即最多接收的数据量。  flags指定接收数据的操作方式可以是0或者以下一个或多个值的逻辑或 MSG_OOB接收带外数据Out-of-Band Data。MSG_PEEK查看数据但不从接收队列中移除数据。MSG_WAITALL等待所有请求的数据直到请求的数量被接收为止。等等。 
返回值 
成功时返回接收到的字节数。如果连接被对方关闭返回0。出错时返回-1并设置errno来指示错误。 
send函数 
send 函数用于向连接的套接字发送数据。函数原型如下 
ssize_t send(int sockfd, const void *buf, size_t len, int flags);参数说明 sockfd指定发送数据的套接字文件描述符。  buf指向要发送数据的指针。  len指定要发送数据的长度。  flags指定发送数据的操作方式可以是0或者以下一个或多个值的逻辑或 MSG_OOB发送带外数据。MSG_DONTROUTE发送数据时不通过网关。等等。 
返回值 
成功时返回发送的字节数。出错时返回-1并设置errno来指示错误。 1.2 readv和writev函数 
readv 和 writev 函数是 Unix 和类 Unix 操作系统中的系统调用它们允许程序在一次操作中从多个缓冲区读取数据或将数据写入多个缓冲区。这些函数对于分散读scatter read和集中写gather write操作非常有用。 
readv函数 
readv 函数用于从文件描述符读取数据到多个缓冲区中。函数原型如下 
ssize_t readv(int fd, const struct iovec *iov, int iovcnt);参数说明 
fd指定要读取数据的文件描述符。iov指向 iovec 结构数组的指针每个 iovec 结构指定一个缓冲区。iovcnt指定 iov 数组中 iovec 结构的数量。 
iovec 结构定义如下 
struct iovec {void  *iov_base; /* Starting address */size_t iov_len;  /* Number of bytes to transfer */
};iov_base指向数据缓冲区的指针。iov_len指定缓冲区的长度。 
返回值 
成功时返回读取的总字节数。如果遇到文件结束返回0。出错时返回-1并设置errno来指示错误。 
writev函数 
writev 函数用于将多个缓冲区的数据写入到文件描述符。函数原型如下 
ssize_t writev(int fd, const struct iovec *iov, int iovcnt);参数说明 
fd指定要写入数据的文件描述符。iov指向 iovec 结构数组的指针每个 iovec 结构指定一个数据源缓冲区。iovcnt指定 iov 数组中 iovec 结构的数量。 
返回值 
成功时返回写入的总字节数。出错时返回-1并设置errno来指示错误。 1.3 recvmsg和recvmsg函数  
recvmsg 和 sendmsg 函数是 Unix 和类 Unix 操作系统中的系统调用它们提供了比 recv 和 send 更高级的接口用于在套接字上发送和接收数据。这些函数支持更多的功能如scatter/gather I/O、控制消息的发送和接收以及带外数据。 
recvmsg函数 
recvmsg 函数用于从套接字接收数据并可以接收辅助数据ancillary data。函数原型如下 
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);参数说明 sockfd指定接收数据的套接字文件描述符。  msg指向 msghdr 结构的指针该结构包含了接收操作的所有参数。  flags指定接收数据的操作方式可以是0或者以下一个或多个值的逻辑或 MSG_OOB接收带外数据。MSG_PEEK查看数据但不从接收队列中移除数据。MSG_WAITALL等待所有请求的数据直到请求的数量被接收为止。等等。 
msghdr 结构定义如下 
struct msghdr {void         *msg_name;       /* Optional address */socklen_t     msg_namelen;    /* Size of address */struct iovec *msg_iov;        /* Scatter/gather array */int           msg_iovlen;     /* # elements in msg_iov */void         *msg_control;    /* Ancillary data, see below */socklen_t     msg_controllen; /* Ancillary data buffer len */int           msg_flags;      /* Flags on received message */
};msg_name 和 msg_namelen用于接收对方地址信息仅用于面向连接的套接字。msg_iov 和 msg_iovlen指定分散读的缓冲区数组 iovec 和其长度。msg_control 和 msg_controllen用于接收辅助数据和控制信息。msg_flags接收消息的标志由系统填充。 
返回值 
成功时返回接收到的字节数。如果连接被对方关闭返回0。出错时返回-1并设置errno来指示错误。 
sendmsg函数 
sendmsg 函数用于向套接字发送数据并可以发送辅助数据。函数原型如下 
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);参数说明 sockfd指定发送数据的套接字文件描述符。  msg指向 msghdr 结构的指针该结构包含了发送操作的所有参数。  flags指定发送数据的操作方式可以是0或者以下一个或多个值的逻辑或 MSG_OOB发送带外数据。MSG_DONTROUTE发送数据时不通过网关。等等。 
返回值 
成功时返回发送的字节数。出错时返回-1并设置errno来指示错误。 1.4 客户—服务器实例 
这个服务器的功能主要是返回客户端输入的数据长度其中使用了I/O函数中的readv和writev。 
服务器端代码 
我这个代码涉及到许多前面的基础知识需要了解的就可以看我上一篇博客 
写文章-CSDN创作中心socket套接字函数-CSDN博客写文章-CSDN创作中心 
#includet_stdio.h
#includet_file.h
#includestdlib.h
#include signal.h
#include sys/types.h
#include sys/socket.h
#include string.h
#include arpa/inet.h
#includeunistd.h
static struct iovec*vsNULL;
void sig_process(int signo){//信号处理函数printf(catch a exit signal..\n);free(vs);_exit(0);
}#define port 8888//端口号
#define backlog 2//最大监听数量//业务处理逻辑
void process_conn_server(int s){char buffer [30];ssize_t size0; //向量的缓冲区//申请3个向量空间struct iovec * v  (struct iovec *)malloc(3*sizeof(struct iovec));if(!v) E_MSG(malloc,-1);vs  v;//挂接全局变量易于释放管理v[0].iov_base buffer;//每个向量十个地址空间v[1].iov_base buffer10;v[2].iov_base buffer20;v[0].iov_len  v[1].iov_len  v[2].iov_len  10;//初始化长度为10for(;;){size  readv(s, v , 3);// 从套接字中读取数据放入数据缓冲区if(size  0){return ;}//构建响应字符sprintf(v[0].iov_base,%d,size);sprintf(v[1].iov_base,bytes alter);sprintf(v[2].iov_base,ogether\n);//设置写入数据的长度v[0].iov_len  strlen(v[0].iov_base);v[1].iov_len  strlen(v[1].iov_base);v[2].iov_len  strlen(v[2].iov_base);writev(s , v , 3);//发送给客户端}}
int main(int argc ,char * argv[])
{int ss ,sc;//服务器和客户端的套接字文件描述符struct  sockaddr_in server_addr;//服务器地址结构struct  sockaddr_in client_addr;//客户端地址结构pid_t pid;//创建子进程进行分叉进行signal(SIGINT,sig_process);//添加sigint信号到信号掩码signal(SIGPIPE,sig_process);ss  socket(AF_INET,SOCK_STREAM,0);// 创建服务器套接字if(ss  0) E_MSG(socket,-1);bzero(server_addr,sizeof(server_addr));//将地址清零server_addr.sin_family  AF_INET;server_addr.sin_addr.s_addr  htons(INADDR_ANY);//本地地址server_addr.sin_porthtons(port);//设置端口//绑定本地到套接字符int err  bind(ss,(struct  sockaddr * )server_addr,sizeof(server_addr));if(err  0)E_MSG(bind,-1);err  listen(ss,backlog);//创建监听队列for(;;){int addrlen  sizeof(struct sockaddr);sc  accept(ss,(struct sockaddr * )client_addr,addrlen);//获取用户套接字if(sc  0)continue;//客户端出错结束这次循环继续监听客户pid  fork();//创建新的子进程来处理当前连接客户端if(pid0){close(ss);// 子进程中关闭服务端process_conn_server(sc);}else {close(sc);//父进程关闭客户端连接继续监听;}}return 0;
} 
客户端代码 
#includet_stdio.h
#includet_file.h
#includestdlib.h
#include signal.h
#include sys/types.h
#include sys/socket.h
#include string.h
#include arpa/inet.h
#includeunistd.h
#define port 8888
static int s;
static struct iovec*vcNULL;
void  sig_proccess(int signo){printf(catch a exit signal..\n);free(vc);_exit(0);
}void sig_pipe(int signo){printf(catch a sigpipe signal..\n);free(vc);_exit(0);}//业务处理函数
void process_conn_client(int s){char buffer [30];ssize_t size0; //向量的缓冲区//申请3个向量空间struct iovec * v  (struct iovec *)malloc(3*sizeof(struct iovec));if(!v) E_MSG(malloc,-1);vc  v;//挂接全局变量易于释放管理v[0].iov_base buffer;//每个向量十个地址空间v[1].iov_base buffer10;v[2].iov_base buffer20;v[0].iov_len  v[1].iov_len  v[2].iov_len  10;//初始化长度为10int i0;for(;;){//从标准输入中读取数据放入缓冲区buffer中size  read(0,v[0].iov_base,10);//只有十个字节if(size0){v[0].iov_len  size;writev(s,v,1);//发送给服务器v[0].iov_len  v[1].iov_len  v[2].iov_len  10;sizereadv(s,v,3);//从服务器读取数据for(i  0;i3;i){if(v[i].iov_len  0){write(1,v[i].iov_base,v[i].iov_len);//将服务区处理后数据输出}}                  }}}
int main(int argc ,char * argv[])
{struct sockaddr_in server_addr;//服务器结构地址int err;if(argc  1){printf(pls input server addr\n);return 0;}//没有输入指令参数signal(SIGINT,sig_proccess);signal(SIGPIPE,sig_pipe);//设置信号掩码s  socket(AF_INET,SOCK_STREAM,0);//创建客户端套接字if(s  0)E_MSG(socket,-1);//设置服务器地址bzero(server_addr,sizeof(server_addr));//将地址清0server_addr.sin_family  AF_INET;server_addr.sin_addr.s_addr  htons(INADDR_ANY);//本地地址server_addr.sin_porthtons(port);//设置端口inet_pton(AF_INET,argv[1],server_addr.sin_addr);//将用户输入的字符串ip转化为二进制ipconnect(s,(struct sockaddr *)server_addr,sizeof(server_addr));//连接服务器process_conn_client(s);return 0;
} 对于这两个代码大家可以仔细阅读我写了非常详细的注释包括信号的处理业务逻辑的处理等等可以将我们整个基础网络知识串联起来 二.I/O模型介绍 
网络编程中的I/O模型主要影响程序如何处理网络套接字的读写操作。以下是几种常见的I/O模型 
2.1 阻塞I/OBlocking I/O 阻塞I/O模型是最简单的I/O模型。当发起一个I/O操作如读或写时如果数据未准备好程序会阻塞直到操作完成。在这段时间内程序无法执行其他任务。 // 阻塞读
char buffer[1024];
read(socket, buffer, sizeof(buffer));2.2非阻塞I/ONon-blocking I/O 
在非阻塞I/O模型中I/O操作不会阻塞程序。如果数据未准备好I/O操作会立即返回一个错误码通常是EAGAIN或EWOULDBLOCK。程序需要定期轮询检查数据是否准备好. 
// 设置套接字为非阻塞模式
int flags  fcntl(socket, F_GETFL, 0);
fcntl(socket, F_SETFL, flags | O_NONBLOCK);// 非阻塞读
char buffer[1024];
while (read(socket, buffer, sizeof(buffer))  -1  errno  EAGAIN) {// 数据未准备好继续做其他事情
}2.3I/O多路复用I/O Multiplexing I/O多路复用允许程序同时监视多个文件描述符等待一个或多个变得“就绪”。这可以通过select、poll、epollLinux特有或kqueueBSD特有系统调用来实现。 
// 使用select进行I/O多路复用
fd_set readfds;
FD_ZERO(readfds);
FD_SET(socket, readfds);select(socket  1, readfds, NULL, NULL, NULL);if (FD_ISSET(socket, readfds)) {char buffer[1024];read(socket, buffer, sizeof(buffer));
}2.4信号驱动I/OSignal-driven I/O 
信号驱动I/O模型中程序通过sigaction系统调用请求内核在文件描述符就绪时发送一个信号。当数据准备好时内核会发送一个SIGIO信号程序可以在信号处理函数中处理数据。  
// 设置信号处理函数
struct sigaction sa;
sa.sa_handler  io_handler;
sigemptyset(sa.sa_mask);
sa.sa_flags  SA_RESTART;
sigaction(SIGIO, sa, NULL);// 设置套接字的所有者
fcntl(socket, F_SETOWN, getpid());// 开启信号驱动I/O
int flags  fcntl(socket, F_GETFL, 0);
fcntl(socket, F_SETFL, flags | O_ASYNC);2.5异步I/OAsynchronous I/O 异步I/O模型中程序发起I/O操作后立即返回无需等待数据准备好。当操作完成时程序会收到通知。这种模型通常通过aio_read、aio_write等系统调用来实现。 
// 异步读
aiocb aio;
memset(aio, 0, sizeof(aio));
aio.aio_fildes  socket;
aio.aio_buf  buffer;
aio.aio_nbytes  sizeof(buffer);
aio.aio_offset  0;aio_read(aio);每种I/O模型都有其适用的场景。例如阻塞I/O适用于简单应用非阻塞I/O和I/O多路复用适用于需要处理多个套接字的应用而异步I/O适用于需要高性能和低延迟的应用。在选择合适的I/O模型时需要考虑应用的特定需求和性能。 三.监视函数  
3.1select和pselect 
在网络编程中select 和 pselect 函数是用于多路复用I/O multiplexing的系统调用它们允许程序同时监视多个文件描述符以判断它们是否准备好进行读、写或异常错误操作。 
select函数 
select 函数的原型如下 
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);参数说明 
nfds需要检查的最高文件描述符加1。通常设置为最大的文件描述符加上1。readfds指向一组文件描述符的指针这些文件描述符需要检查是否准备好读取数据。writefds指向一组文件描述符的指针这些文件描述符需要检查是否准备好写入数据。exceptfds指向一组文件描述符的指针这些文件描述符需要检查是否发生异常。timeout指向 timeval 结构的指针用于指定 select 应该阻塞等待的最大时间。如果设置为 NULLselect 将无限期地等待如果设置为0select 将立即返回。 
timeval 结构定义如下 
struct timeval {long    tv_sec;         /* seconds */long    tv_usec;        /* microseconds */
};返回值 
成功时返回准备好的文件描述符的数量。如果超时返回0。出错时返回-1并设置errno来指示错误。 
使用 select 时需要使用 FD_ZERO、FD_SET 和 FD_CLR 宏来操作 fd_set 集合。 
pselect函数 
pselect 函数与 select 类似但它提供了一些额外的功能特别是在处理信号方面。pselect 的原型如下 
int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask);参数说明 
前四个参数与 select 函数相同。timeout指向 timespec 结构的指针用于指定 pselect 应该阻塞等待的最大时间。timespec 结构与 timeval 类似但它使用秒和纳秒来表示时间。sigmask指向 sigset_t 类型的一个信号集的指针用于在 pselect 调用期间临时替换进程的信号掩码。这意味着 pselect 在等待文件描述符就绪时会阻塞指定的信号。 
timespec 结构定义如下 
struct timespec {time_t  tv_sec;         /* seconds */long    tv_nsec;        /* nanoseconds */
};返回值 
成功时返回准备好的文件描述符的数量。如果超时返回0。出错时返回-1并设置errno来指示错误。 
例子 
#include stdio.h
#include stdlib.h
#include unistd.h
#include sys/select.hint main() {fd_set readfds;struct timeval timeout;int result;FD_ZERO(readfds);FD_SET(0, readfds); // 监视标准输入文件描述符0timeout.tv_sec  5; // 设置超时时间为5秒timeout.tv_usec  0;result  select(1, readfds, NULL, NULL, timeout);if (result  -1) {perror(select);exit(EXIT_FAILURE);} else if (result  0) {printf(Data is available to read.\n);} else {printf(Timeout occurred.\n);}return 0;
}在这个例子中我们使用 select 来监视标准输入文件描述符0设置超时时间为5秒。如果在这段时间内有数据可读select 将返回大于0的值如果超时将返回0如果发生错误将返回-1。 
3.2poll函数和ppoll函数 poll 和 ppoll 函数是 Unix 和类 Unix 操作系统中的系统调用用于多路复用I/O multiplexing允许程序同时监视多个文件描述符的读写状态。与 select 和 pselect 函数相比poll 和 ppoll 提供了更丰富的接口和更好的性能。 
poll函数 
poll 函数的原型如下 
int poll(struct pollfd *fds, nfds_t nfds, int timeout);参数说明 
fds指向一个 pollfd 结构数组的指针每个结构描述了一个要监视的文件描述符。nfds指定 fds 数组中 pollfd 结构的数量。timeout指定 poll 应该阻塞等待的最大时间毫秒。如果设置为-1poll 将无限期地等待如果设置为0poll 将立即返回。 
pollfd 结构定义如下 
struct pollfd {int   fd;         /* file descriptor */short events;     /* requested events */short revents;    /* returned events */
};fd要监视的文件描述符。events请求监视的 events通过位掩码指定。revents返回时表示实际发生的事件通过位掩码指定。 
events 和 revents 可以是以下标志的组合定义在 poll.h 头文件中 
POLLIN有数据可读。POLLOUT可以写数据。POLLERR发生错误。POLLHUP挂起。POLLNVAL无效的请求。 
返回值 
成功时返回准备好的文件描述符的数量。如果超时返回0。出错时返回-1并设置errno来指示错误。 
ppoll函数 
ppoll 函数与 poll 类似但它提供了一些额外的功能特别是在处理信号方面。ppoll 的原型如下 
int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout, const sigset_t *sigmask);参数说明 
前三个参数与 poll 函数相同。timeout指向 timespec 结构的指针用于指定 ppoll 应该阻塞等待的最大时间。timespec 结构与 timeval 类似但它使用秒和纳秒来表示时间。sigmask指向 sigset_t 类型的一个信号集的指针用于在 ppoll 调用期间临时替换进程的信号掩码。这意味着 ppoll 在等待文件描述符就绪时会阻塞指定的信号。 
返回值 
成功时返回准备好的文件描述符的数量。如果超时返回0。出错时返回-1并设置errno来指示错误。 
例子 
#include stdio.h
#include stdlib.h
#include unistd.h
#include poll.hint main() {struct pollfd fds[1];int result;fds[0].fd  0; // 监视标准输入文件描述符0fds[0].events  POLLIN; // 监视可读事件result  poll(fds, 1, 5000); // 设置超时时间为5000毫秒if (result  -1) {perror(poll);exit(EXIT_FAILURE);} else if (result  0) {if (fds[0].revents  POLLIN) {printf(Data is available to read.\n);}} else {printf(Timeout occurred.\n);}return 0;
}在这个例子中我们使用 poll 来监视标准输入文件描述符0设置超时时间为5000毫秒。如果在这段时间内有数据可读poll 将返回大于0的值如果超时将返回0如果发生错误将返回-1。 四.总结 
这篇文章对数据I/O进行了整体的介绍包括recv ,send, readv , writev,recmsg , sendmsg等I/O函数,并且给了很多例子来介绍I/O的各种模型及其使用相信经过这篇文章的学习大家对网络编程中的I/O操作能有个整体认知 
 文章转载自: http://www.morning.wxrbl.cn.gov.cn.wxrbl.cn http://www.morning.wdlyt.cn.gov.cn.wdlyt.cn http://www.morning.qjzgj.cn.gov.cn.qjzgj.cn http://www.morning.jbshh.cn.gov.cn.jbshh.cn http://www.morning.wjplm.cn.gov.cn.wjplm.cn http://www.morning.npbkx.cn.gov.cn.npbkx.cn http://www.morning.frpm.cn.gov.cn.frpm.cn http://www.morning.hxcuvg.cn.gov.cn.hxcuvg.cn http://www.morning.xnymt.cn.gov.cn.xnymt.cn http://www.morning.nbiotank.com.gov.cn.nbiotank.com http://www.morning.pltbd.cn.gov.cn.pltbd.cn http://www.morning.zlnkq.cn.gov.cn.zlnkq.cn http://www.morning.rkdhh.cn.gov.cn.rkdhh.cn http://www.morning.xcyhy.cn.gov.cn.xcyhy.cn http://www.morning.zcwtl.cn.gov.cn.zcwtl.cn http://www.morning.rpljf.cn.gov.cn.rpljf.cn http://www.morning.jcjgh.cn.gov.cn.jcjgh.cn http://www.morning.mbnhr.cn.gov.cn.mbnhr.cn http://www.morning.hzqjgas.com.gov.cn.hzqjgas.com http://www.morning.mnwb.cn.gov.cn.mnwb.cn http://www.morning.bdtpd.cn.gov.cn.bdtpd.cn http://www.morning.zmyhn.cn.gov.cn.zmyhn.cn http://www.morning.nzsdr.cn.gov.cn.nzsdr.cn http://www.morning.nslwj.cn.gov.cn.nslwj.cn http://www.morning.fdzzh.cn.gov.cn.fdzzh.cn http://www.morning.dyrzm.cn.gov.cn.dyrzm.cn http://www.morning.jhrqn.cn.gov.cn.jhrqn.cn http://www.morning.dqkcn.cn.gov.cn.dqkcn.cn http://www.morning.zcsyz.cn.gov.cn.zcsyz.cn http://www.morning.yrbp.cn.gov.cn.yrbp.cn http://www.morning.qysnd.cn.gov.cn.qysnd.cn http://www.morning.dmzzt.cn.gov.cn.dmzzt.cn http://www.morning.wsxly.cn.gov.cn.wsxly.cn http://www.morning.yfstt.cn.gov.cn.yfstt.cn http://www.morning.mtcnl.cn.gov.cn.mtcnl.cn http://www.morning.xglgm.cn.gov.cn.xglgm.cn http://www.morning.rdmz.cn.gov.cn.rdmz.cn http://www.morning.qlkjh.cn.gov.cn.qlkjh.cn http://www.morning.ncfky.cn.gov.cn.ncfky.cn http://www.morning.xhxsr.cn.gov.cn.xhxsr.cn http://www.morning.leyuhh.com.gov.cn.leyuhh.com http://www.morning.nqrlz.cn.gov.cn.nqrlz.cn http://www.morning.bwjws.cn.gov.cn.bwjws.cn http://www.morning.qpljg.cn.gov.cn.qpljg.cn http://www.morning.fqlxg.cn.gov.cn.fqlxg.cn http://www.morning.btwrj.cn.gov.cn.btwrj.cn http://www.morning.ctfh.cn.gov.cn.ctfh.cn http://www.morning.knpmj.cn.gov.cn.knpmj.cn http://www.morning.aishuxue.com.cn.gov.cn.aishuxue.com.cn http://www.morning.jpqmq.cn.gov.cn.jpqmq.cn http://www.morning.txmkx.cn.gov.cn.txmkx.cn http://www.morning.tgdys.cn.gov.cn.tgdys.cn http://www.morning.fllfz.cn.gov.cn.fllfz.cn http://www.morning.wjtxt.cn.gov.cn.wjtxt.cn http://www.morning.krqhw.cn.gov.cn.krqhw.cn http://www.morning.bauul.com.gov.cn.bauul.com http://www.morning.rhqn.cn.gov.cn.rhqn.cn http://www.morning.gjlxn.cn.gov.cn.gjlxn.cn http://www.morning.jphxt.cn.gov.cn.jphxt.cn http://www.morning.pjqxk.cn.gov.cn.pjqxk.cn http://www.morning.jcxyq.cn.gov.cn.jcxyq.cn http://www.morning.rgkd.cn.gov.cn.rgkd.cn http://www.morning.qnypp.cn.gov.cn.qnypp.cn http://www.morning.pxdgy.cn.gov.cn.pxdgy.cn http://www.morning.nynlf.cn.gov.cn.nynlf.cn http://www.morning.kzrbn.cn.gov.cn.kzrbn.cn http://www.morning.lsmnn.cn.gov.cn.lsmnn.cn http://www.morning.srltq.cn.gov.cn.srltq.cn http://www.morning.hpprx.cn.gov.cn.hpprx.cn http://www.morning.xflzm.cn.gov.cn.xflzm.cn http://www.morning.rtspr.cn.gov.cn.rtspr.cn http://www.morning.sjftk.cn.gov.cn.sjftk.cn http://www.morning.kqbzy.cn.gov.cn.kqbzy.cn http://www.morning.nhzps.cn.gov.cn.nhzps.cn http://www.morning.pqjlp.cn.gov.cn.pqjlp.cn http://www.morning.qmncj.cn.gov.cn.qmncj.cn http://www.morning.rcbdn.cn.gov.cn.rcbdn.cn http://www.morning.skcmt.cn.gov.cn.skcmt.cn http://www.morning.tgnwt.cn.gov.cn.tgnwt.cn http://www.morning.ndngj.cn.gov.cn.ndngj.cn