网站定制一般价格多少,邢台做网站名列前茅,专业做网站优化价格,长春网站建设哪里好目录
✈必备知识
进程间通信概述
#x1f525;概述
#x1f525;必要性
#x1f525;原理
管道概述
#x1f525;管道的本质
#x1f525;管道的相关特性
#x1f525;管道的同步与互斥机制
匿名管道
#x1f525;系统调用接口介绍
#x1f525;内核原理
…目录
✈必备知识
进程间通信概述
概述
必要性
原理
管道概述
管道的本质
管道的相关特性
管道的同步与互斥机制
匿名管道
系统调用接口介绍
内核原理
匿名管道小实战——进程池
命名管道
概述
创建命名管道的指令
创建命名管道函数
system V共享内存
概述
系统调用接口
代码示例
消息队列
原理概述
接口介绍
创建消息队列
向消息队列发送消息
从消息队列接收消息
控制消息队列
信号量
概述
接口介绍
OS管理共享内存消息队列信号量 个人主页东洛的克莱斯韦克 ✈必备知识
进程地址空间
进程控制——进程创建进程退出进程等待
理解文件系统
进程间通信概述 概述
进程间通信简称IPC是在不同进程之间传播或交换信息的一种机制。
管道是基于内存级文件的通信方案
在System V解决方案中有共享内存消息队列信号量。在POSIX IPC解决方案中有共享内存消息队列信号量互斥量条件变量读写锁
这些通信方案在系统中都属于IPC资源。
必要性
每个进程都有自己的地址空间这保证了进程的独立性。即使两个进程是父子关系可以看到同一份数据但只要有一方进行写入操作都会发生写时拷贝。
进程A异常了不会影响到进程B,进程C......本质上来讲进程的独立性是因为进程间的数据具有独立性。
进程具有独立性是在内核设计时就有的理念。但后来发现进程有时相互传输数据是必要的所以必须提出解决方案——不破坏进程的独立性又能实现进程的通信。
原理
先让两个进程看到同一份公共资源这公共资源可以是文件也可以是一块内存。
进程A向公共资源写入数据进程B向公共资源读数据。此时两个进程完成了数据的交互这样进程A和进程B就实现了通信。
管道概述 管道的本质
管道也是文件的一种属于p类型的文件。管道文件属于公共资源如果多个进程打开同一个管道文件就能相互传输数据。
管道文件是内存级文件它在磁盘中并没有对应的数据块来为它保存文件内容。系统只会在内存中为管道文件开辟文件缓冲区来保存数据。这样做避免了内存与外设的IO交互提高进程间通信效率。
管道文件在磁盘中有个简单的映像这个映像的大小为 0 这么做是为了让文件系统知道有这么一个文件存在。
管道的相关特性
管道一般是单向通信——一方是读端一方是写端管道具有同步与互斥机制——保护数据管道的生命周期随进程——被打开的文件的声明周期随进程管道是面向字节流的
管道的同步与互斥机制
同步与互斥机制是为了保护管道数据的安全
读写端都正常管道为空读端阻塞读写端都正常管道为满写端阻塞读端正常写端关闭读端会读到 0 相当于读到文件结尾进程正常执行后续代码读端关闭写端正常写端的进程会被信号杀掉进程异常终止
匿名管道
匿名管道本质上是没有名字的内存级的文件——适用于具有血缘关系的进程
系统调用接口介绍 头文件 #include unistd.h 功能 : 创建匿名管道 原型 int pipe(int fd[2]); 参数 fd文件描述符数组 , 其中 fd[0]表示读端 , fd[1]表示写端 返回值 : 成功返回 0 失败返回错误代码 内核原理
在使用pipe系统调用之后系统会为该进程分配两个文件描述符——files_struct数组下标。会有两个file结构体指向同一个文件缓冲区。分别以只读和只写打开文件缓冲区。 使用fork系统调用之后子进程会继承父进程的内核数据也包括了对应的文件描述符。此时父子进程已经能看到同一份公共资源了——有了通信的基础。
父进程和子进程分别关掉一端文件描述符就能实现通信啦~ 匿名管道小实战——进程池
与进程池概念类似的还有内存池。这些都属于池化技术——申请资源时申请走一大块资源用户层把这些资源维护起来在需要申请资源的时候不用再向系统中申请提高程序的效率。
我们要设计的进程池基本原理如下
父进程创建一批子进程父子进程用匿名管道通信父进程只要不向管道里写数据子进程就会一直阻塞因为父进程是写端子进程是读端。
父进程想让子进程执行任务时不需要再向OS申请进程直接选一个在阻塞状态的子进程即可。 代码示例
#include stdio.h
#include stdlib.h
#include vector
#include unistd.h
#include ctime
#include sys/types.h
#include sys/wait.h
#include iostream
using namespace std;
#define PID_QUANTITY 10 // 子进程数量
#define NUMBER_OF_BYTES 4// 子进程一次读取的字节数
#define SEND 10//父进程发送消息的数量class pipeline // 描述进程池属性
{
public:pipeline(int fd, pid_t pid) // 构造函数: _fd(fd), _pid(pid){}int _fd; // 文件描述符pid_t _pid; // 进程pid
};void reception() // 子进程接收任务
{int tmp 0;while (true){int i read(0, tmp, NUMBER_OF_BYTES); // 从信道里读取if (NUMBER_OF_BYTES i){printf(我是子进程%d我读到的数据是%d\n, getpid(), tmp);}if (0 i)break;}
}void Cistern(std::vectorpipeline *vp) // 创建进程池,输出型参数vectorpipeline * vp
{std::vectorint oldfds;for (int i 0; i PID_QUANTITY; i){int fds[2]; // 0下标表示读端1下表表示写端 pipe(fds); // 建立信道pid_t tmp_pid fork(); // 创建子进程if (0 tmp_pid) // 子进程{for (auto fd : oldfds) // 关闭子进程多余的写端{close(fd);}close(fds[1]); // 关闭子进程写端dup2(fds[0], 0); // 本来从键盘读取变为从信道读取减少传参close(fds[0]); // 关闭多余的读端reception(); // 接收任务exit(0); // 子进程结束}close(fds[0]); // 关闭父进程读端vp-push_back(pipeline(fds[1], tmp_pid)); // 向父进程管理的进程池中添加字段父进程信道的文件描述符以及子进程的pidoldfds.push_back(fds[1]); // 记录子进程的写端方便下一个进程继承后关闭~}
}void Reclaim(std::vectorpipeline vp) // 回收子进程
{for (auto c : vp)
{close(c._fd);waitpid(c._pid, nullptr, 0);
}}void Send(std::vectorpipeline vp) //向子进程发消息
{for (int k 0; k SEND; k) {int i rand() % 10;int j rand() % 10;write(vp[i]._fd, j, sizeof(int));printf(我是父进程我向子进程传递的数据是%d\n, j);sleep(1); }
}int main()
{srand(time(nullptr) ^ getpid() ^ 1023); // 种一个随机数种子std::vectorpipeline pv; // 创建容器管理进程池Cistern(pv); // 初始化Send(pv); // 父进程派发任务Reclaim(pv); // 关闭信道和等待子进程return 0;
}
命名管道
概述
命名管道的本质是具有名字的内存级文件。
使用命名管道通信无需在意进程间是否具有血缘关系。只要不同的进程能打开同一个命名管道文件——就有了通信的基础。
对命名管道文件的操作只需像普通文件操作一样调用系统的文件操作接口即可如open close read write lseek
创建命名管道的指令 mkfifo 文件名
创建命名管道函数
头文件
#include sys/stat.h
#include fcntl.h
函数原型
int mkfifo(const char *filename,mode_t mode);
参数
filename指向以 null 结尾的字符串的指针该字符串指定了命名管道的名称包括路径。如果指定的文件已存在且不是一个命名管道mkfifo 会失败。
mode指定了命名管道的权限与 open 或 creat 函数中的 mode 参数类似。这些权限会受到进程的文件模式创建掩码umask的影响。
返回值
成功时mkfifo 返回 0出错时返回 -1。
system V共享内存
概述
进程间通信的基础是让不同进程看到同一份资源为了达到这种目的共享内存是一种更直接的方案。
OS会在物理内存中开辟一块空间这块空间就是公共资源。只要把这块公共资源挂接到相应进程的地址空间上就实现了通信的基础。
只要把内存挂接到进程的地址空间的内存映射段上该进程就有对该空间的读写权限。每一个进程都会认为该空间是自己的那么进程之间在传输数据时不会考虑彼此的感受。换句话说共享内存没有同步与互斥的保护机制。
进程地址空间示意图 但共享内存的通信方案时最快的。只要进程A把数据刷到共享内存中其他进程就能立马拿到数据。 系统调用接口 key_t ftok(const char *pathname, int proj_id);pathname指定字符串一般是文件路径 proj_id指定一个整数 通过上述的参数 ftok系统调用会通过一系列的算法生成一个 key值给的参数越具有唯一性ftok系统调用生成的 key值越不容易冲突。 int shmget(key_t key, size_t size, int shmflg); 功能创建一块共享内存 参数第一个参数是key值是内核标识IPC资源的唯一标识符。
第二个参数size则指定共享内存的大小建议传入40964KB的整数倍,如果传入了4097那么系统会申请4096 * 2 的大小因为系统申请内存是以4KB为单位大小申请的。但用户层只能用4097大小的内存。
第三个参数传入权限码和选项。0666 | IPC_CREAT|IPC_EXCL这样传表示创建新的、唯一的共享内存段并且权限为0666。值传入IPC_CREAT表示要获取返回值。
返回值该函数的返回值表示用户层的key值。也就是说用户层不使用ftok返回的key值而是使用shmget返回的值。 void *shmat(int shmid, const void *shmaddr, int shmflg);
功能把共享内存挂接到地址空间
参数第一个参数是shmget的返回值。第二个表示要挂接到进程地址空间的什么位置设为nullptr即可表示让系统指定。第三个传 0即可。 返回值成功返回一个指针指向共享内存第一个节失败返回 -1 int shmdt(const void *shmaddr);
功能地址空间和共享内存去关联
参数指向共享内存第一个节也就是shmat的返回值 返回值 成功返回 0 失败返回 -1 将共享内存段与当前进程脱离不等于删除共享内存段 代码示例
IPC.hpp
#include stdio.h
#include stdlib.h
#include string.h
#include sys/ipc.h
#include sys/shm.h
#include unistd.h
#include sys/types.h key_t Ftok() //获取key值
{key_t key ftok(/home/ccc/d2, s); return key;
}int Shmget(int i) //创建
{int shm_id;size_t shm_size 4096; // 共享内存段的大小例如1024字节key_t key Ftok();shm_id shmget(key, shm_size, i); return shm_id;
}int createshm() //创建
{return Shmget(0666 | IPC_CREAT|IPC_EXCL);//权限 | 创建 有的话就获取 | 创建新的、唯一的共享内存段
}int getshm() //获取
{return Shmget(IPC_CREAT);
}
Client.cc
// 客户端
#include IPC.hppint main()
{int shm_id getshm();char *ptr (char *)shmat(shm_id, nullptr, 0); // 挂接printf(%s, ptr);sleep(15);shmdt(ptr);return 0;
}
Server.cc
// 服务端
#include IPC.hppint main()
{int shm_id createshm(); char* ptr (char*)shmat(shm_id, nullptr, 0); strcpy(ptr, 你是个小可爱);printf(%s, ptr);sleep(15);shmdt(ptr);return 0;
} 消息队列
原理概述
这种通信方案的公共资源是由内核维护的一种数据结构——队列。
不同进程间需要先看到同一个消息队列这样就有了通信的基础。进程向消息队列发送的是一个个带类型的数据块带类型是为了区分该数据块是由那个进程发送的其他进程只需要取走不属于自己的数据块就可以实现通信了。
接口介绍
创建消息队列
int msgget(key_t key, int msgflg);
参数
key消息队列的标识符通常通过ftok函数生成。msgflg创建标志常用的有IPC_CREAT如果不存在则创建和IPC_EXCL与IPC_CREAT一起使用时如果队列已存在则创建失败。还可以按位或上权限值如0666来设置队列的权限。
返回值
成功时返回消息队列的ID。失败时返回-1并设置errno以指示错误原因。
向消息队列发送消息
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数
msqid消息队列的ID。msgp指向要发送的消息的指针通常是一个结构体其第一个成员为消息类型long类型后续为消息数据。msgsz消息的大小不包括消息类型即msgp指向的结构体中消息数据的长度。msgflg控制标志常用的有0阻塞发送和IPC_NOWAIT非阻塞发送。
返回值
成功时返回0。失败时返回-1并设置errno以指示错误原因。
从消息队列接收消息
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
参数
msqid消息队列的ID。msgp指向接收消息的缓冲区的指针该缓冲区应与发送消息时使用的结构体类型相同。msgsz缓冲区的最大长度即能接收的最大消息大小不包括消息类型。msgtyp消息类型用于指定接收哪种类型的消息。可以指定为0、正数或负数具体含义见参考文章。msgflg控制标志常用的有0阻塞接收和IPC_NOWAIT非阻塞接收。
返回值
成功时返回实际接收到的消息大小不包括消息类型。失败时返回-1并设置errno以指示错误原因。
控制消息队列
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
参数
msqid消息队列的ID。cmd控制命令常用的有IPC_STAT获取消息队列的状态、IPC_SET设置消息队列的属性和IPC_RMID删除消息队列。buf指向msqid_ds结构体的指针用于存储或设置消息队列的状态和属性。
返回值
成功时返回0。失败时返回-1并设置errno以指示错误原因。
信号量
概述
信号量本质是一把计数器 互斥任何时刻只允许一个执行流访问资源 临界资源共享的只能被一个执行流访问的资源 临界区访问临界资源的代码 访问公共资源时不能直接访问而是要让计数器减减。也就是说要想申请访问公共资源必须访问计数器资源如果计数器资源为 0 就不能访问公共资源。
如果计数器资源为 1 ——二元信号量那么只能有一个执行流再访问公共资源这就时互斥也是锁。 计数器资源也会被多个执行流访问那么计数器资源也是公共资源。如果如果信号量要保证公共资源的安全性就必须保证自己的计数操作是原子性的。
原子性本质就是两态性即一件事要么没有做要么做完了没有正在做的状态。
对计数器减减称为 P 操作对计数器加加称为 V操作。PV操作是原子性的
接口介绍
创建或获取信号量集
int semget(key_t key, int nsems, int sem_flags);参数
key用于标识信号量集的键值通常使用ftok函数生成。nsems信号量集中包含的信号量数量通常为1。sem_flags用于指定信号量的权限和标志常用的标志包括IPC_CREAT如果不存在则创建、IPC_EXCL与IPC_CREAT一起使用确保创建的信号量集是唯一的。
返回值
成功时返回信号量集的标识符semid失败时返回-1。
控制信号量集
int semctl(int semid, int semnum, int cmd, ...);参数说明
semid信号量集的标识符。semnum信号量的索引通常为0如果信号量集中只有一个信号量。cmd控制命令用于指定要进行的操作如SETVAL设置信号量的值、IPC_RMID删除信号量集等。...根据cmd的不同可能需要额外的参数如使用SETVAL时需要指定信号量的新值。
返回值根据不同的命令返回不同的值。
操作信号量
int semop(int semid, struct sembuf *sops, unsigned nsops);
参数
semid信号量集的标识符。sops指向sembuf结构体数组的指针每个sembuf结构体描述了一个对信号量的操作。nsopssops数组中结构体的数量即要执行的操作数。
sembuf结构体
struct sembuf { unsigned short sem_num; // 信号量在信号量集中的索引 short sem_op; // 操作值正数表示V操作释放信号量负数表示P操作等待信号量 short sem_flg; // 操作标志位如SEM_UNDO使操作系统跟踪信号量并在进程终止时自动释放
};
返回值
成功时返回0失败时返回-1。
OS管理共享内存消息队列信号量 操作系统为了管理这些IPC资源必须先用结构体描述这些IPC资源。如下是内核显示给用户层的部分内核数据字段
共享内存 struct shmid_ds { ipc_perm shm_perm这是一个ipc_perm结构体包含了共享内存段的权限和所有权信息如UID用户ID、GID组ID、权限模式读写执行等。 shm_segsz共享内存段的大小以字节为单位。 shm_atime最后一次附加attach到共享内存段的时间。 shm_dtime最后一次从共享内存段分离detach的时间。 shm_ctime共享内存段最后一次改变的时间如权限或所有权改变。 shm_cpid创建共享内存段的进程的PID进程ID。 shm_lpid最后一次执行shmat附加或shmdt分离操作的进程的PID。 shm_nattch当前附加到共享内存段的进程数。 } 消息队列 struct msqid_ds { ipc_perm msg_perm这是一个ipc_perm结构体包含了消息队列的权限和所有权信息。 key用于msgget系统调用的键用于获取消息队列的标识符。 msg_stime最后一次msgsnd发送消息操作的时间。 msg_rtime最后一次msgrcv接收消息操作的时间。 uid、gid消息队列拥有者的有效UID和GID。 cuid、cgid创建消息队列的进程的有效UID和GID。 msg_ctime消息队列最后一次改变的时间如权限或所有权改变。 msg_qbytes消息队列的最大字节数。 msg_qnum消息队列中当前的消息数。 msg_lspid、msg_lrpid未在文本中直接列出但通常存在最后发送消息和最后接收消息的进程的PID。 } 信号量 struct semid_ds { ipc_perm sem_perm这是一个ipc_perm结构体包含了信号量集的权限和所有权信息。 sem_otime最后一次semop信号量操作操作的时间。 sem_ctime信号量集最后一次改变的时间如权限或所有权改变。 sem_nsems信号量集中的信号量数量。 } ipc_perm struct ipc_perm { keyIPC 对象的键key。这是一个用于唯一标识 IPC 对象的值尽管它并不直接用于权限控制但在创建 IPC 对象时作为查找或创建对象的依据。 uid用户标识符User ID。这表示 IPC 对象的拥有者的用户 ID。只有拥有者或其具有适当权限的进程才能修改 IPC 对象的某些属性。 gid组标识符Group ID。这表示 IPC 对象所属的组。组内的成员可能具有访问 IPC 对象的特定权限。 cuid创建者用户标识符Creators User ID。这表示创建 IPC 对象的进程的用户 ID。这个字段通常用于记录谁创建了 IPC 对象但它本身并不直接用于权限控制。 cgid创建者组标识符Creators Group ID。这表示创建 IPC 对象的进程的组 ID。与 cuid 类似这个字段用于记录谁创建了 IPC 对象但本身不直接用于权限检查。 mode权限模式。这个字段是一个位掩码指定了 IPC 对象的访问权限。这些权限通常包括读r、写w和执行x权限但对于 IPC 对象来说“执行”权限并不适用。相反这些权限位用于控制对 IPC 对象的访问如读取消息、写入消息、修改信号量值等。权限位可以分别设置给拥有者user即 uid、组group即 gid和其他others用户。 seq序列号Sequence Number。这是一个内部使用的字段用于内核中跟踪 IPC 对象的版本或变化。它对于用户空间程序来说通常是不透明的。 } 共享内存消息队列信号量他们之间的通信方式肯定有差异但也有相同的属性这些相同的属性被放在ipc_perm结构体中ipc_perm就是基类shmid_dsmsqid_dssemid_ds就是派生类。
内核中用一个数组储存ipc_perm类型指针ipc_perm类型指针可能指向不同的IPC资源这就是面向对象中多态的概念。 内核反馈给用户层的就是该数组的下标。该数组下标是分配是线性递增的即使删除了IPC资源反馈给用户层的数组也是线性递增的。当增到某个阈值值就会回绕也就是再从 0 开始。 文章转载自: http://www.morning.jypqx.cn.gov.cn.jypqx.cn http://www.morning.dtgjt.cn.gov.cn.dtgjt.cn http://www.morning.cfcpb.cn.gov.cn.cfcpb.cn http://www.morning.xysxj.com.gov.cn.xysxj.com http://www.morning.zrmxp.cn.gov.cn.zrmxp.cn http://www.morning.rxydr.cn.gov.cn.rxydr.cn http://www.morning.tmlhh.cn.gov.cn.tmlhh.cn http://www.morning.ljbpk.cn.gov.cn.ljbpk.cn http://www.morning.fewhope.com.gov.cn.fewhope.com http://www.morning.cmcjp.cn.gov.cn.cmcjp.cn http://www.morning.mjqms.cn.gov.cn.mjqms.cn http://www.morning.skmzm.cn.gov.cn.skmzm.cn http://www.morning.ydrfl.cn.gov.cn.ydrfl.cn http://www.morning.fywqr.cn.gov.cn.fywqr.cn http://www.morning.rqxch.cn.gov.cn.rqxch.cn http://www.morning.yhjrc.cn.gov.cn.yhjrc.cn http://www.morning.mtgnd.cn.gov.cn.mtgnd.cn http://www.morning.bpmnx.cn.gov.cn.bpmnx.cn http://www.morning.rczrq.cn.gov.cn.rczrq.cn http://www.morning.dhyqg.cn.gov.cn.dhyqg.cn http://www.morning.ktlxk.cn.gov.cn.ktlxk.cn http://www.morning.ylqrc.cn.gov.cn.ylqrc.cn http://www.morning.wkwds.cn.gov.cn.wkwds.cn http://www.morning.rnngz.cn.gov.cn.rnngz.cn http://www.morning.kcyxs.cn.gov.cn.kcyxs.cn http://www.morning.rpzth.cn.gov.cn.rpzth.cn http://www.morning.rwjtf.cn.gov.cn.rwjtf.cn http://www.morning.wfcqr.cn.gov.cn.wfcqr.cn http://www.morning.drcnn.cn.gov.cn.drcnn.cn http://www.morning.plqhb.cn.gov.cn.plqhb.cn http://www.morning.grbp.cn.gov.cn.grbp.cn http://www.morning.kzxlc.cn.gov.cn.kzxlc.cn http://www.morning.wqjpl.cn.gov.cn.wqjpl.cn http://www.morning.wbnsf.cn.gov.cn.wbnsf.cn http://www.morning.nhdw.cn.gov.cn.nhdw.cn http://www.morning.hrhwn.cn.gov.cn.hrhwn.cn http://www.morning.szoptic.com.gov.cn.szoptic.com http://www.morning.fjlsfs.com.gov.cn.fjlsfs.com http://www.morning.jfmyt.cn.gov.cn.jfmyt.cn http://www.morning.pwlxy.cn.gov.cn.pwlxy.cn http://www.morning.flchj.cn.gov.cn.flchj.cn http://www.morning.tkqzr.cn.gov.cn.tkqzr.cn http://www.morning.msxhb.cn.gov.cn.msxhb.cn http://www.morning.cyfsl.cn.gov.cn.cyfsl.cn http://www.morning.fqklt.cn.gov.cn.fqklt.cn http://www.morning.uycvv.cn.gov.cn.uycvv.cn http://www.morning.bccls.cn.gov.cn.bccls.cn http://www.morning.nbgfk.cn.gov.cn.nbgfk.cn http://www.morning.tdxnz.cn.gov.cn.tdxnz.cn http://www.morning.qnbgk.cn.gov.cn.qnbgk.cn http://www.morning.fpzpb.cn.gov.cn.fpzpb.cn http://www.morning.rfbpq.cn.gov.cn.rfbpq.cn http://www.morning.fbdkb.cn.gov.cn.fbdkb.cn http://www.morning.bssjp.cn.gov.cn.bssjp.cn http://www.morning.gmwqd.cn.gov.cn.gmwqd.cn http://www.morning.yrjym.cn.gov.cn.yrjym.cn http://www.morning.ymyhg.cn.gov.cn.ymyhg.cn http://www.morning.wnjsp.cn.gov.cn.wnjsp.cn http://www.morning.xlbtz.cn.gov.cn.xlbtz.cn http://www.morning.npbnc.cn.gov.cn.npbnc.cn http://www.morning.rpstb.cn.gov.cn.rpstb.cn http://www.morning.lwgsk.cn.gov.cn.lwgsk.cn http://www.morning.lqqqh.cn.gov.cn.lqqqh.cn http://www.morning.hsrpc.cn.gov.cn.hsrpc.cn http://www.morning.lthtp.cn.gov.cn.lthtp.cn http://www.morning.trrd.cn.gov.cn.trrd.cn http://www.morning.wqhlj.cn.gov.cn.wqhlj.cn http://www.morning.kdxzy.cn.gov.cn.kdxzy.cn http://www.morning.lgwjh.cn.gov.cn.lgwjh.cn http://www.morning.brkrt.cn.gov.cn.brkrt.cn http://www.morning.gfmpk.cn.gov.cn.gfmpk.cn http://www.morning.hyjpl.cn.gov.cn.hyjpl.cn http://www.morning.qwqzk.cn.gov.cn.qwqzk.cn http://www.morning.rjynd.cn.gov.cn.rjynd.cn http://www.morning.pmxw.cn.gov.cn.pmxw.cn http://www.morning.qwqzk.cn.gov.cn.qwqzk.cn http://www.morning.lmdkn.cn.gov.cn.lmdkn.cn http://www.morning.tgcw.cn.gov.cn.tgcw.cn http://www.morning.rtryr.cn.gov.cn.rtryr.cn http://www.morning.xnfg.cn.gov.cn.xnfg.cn