网站建设说辞,网站开发 兼职项目,php做网站的优势,哪里可以做网站的文章目录 BIODEMO 1DEMO 2小结论单线程BIO的缺陷BIO如何处理并发多线程BIO服务器的弊端 NIONIO要解决的问题模拟NIO方案一#xff1a; #xff08;等待连接时和等待数据时不阻塞#xff09;方案二#xff08;缓存Socket#xff0c;轮询数据是否准备好#xff09;方案二存… 文章目录 BIODEMO 1DEMO 2小结论单线程BIO的缺陷BIO如何处理并发多线程BIO服务器的弊端 NIONIO要解决的问题模拟NIO方案一 等待连接时和等待数据时不阻塞方案二缓存Socket轮询数据是否准备好方案二存在的问题 NIO是如何解决这些问题的使用select/poll/epoll和直接在应用层做轮询的区别select底层逻辑poll的底层逻辑epoll的底层逻辑 BIO VS NIOStream vs. BufferBlocking vs. Non-blockingSelectorsNIO和经典IO如何影响应用程序的设计API调用NIO或IO类数据处理Java IO从阻塞流中读取数据Java NIO从通道读取数据直到所有需要的数据都在缓冲区中 适用场景通俗解释 BIO
要讲明白BIO和NIO首先我们应该自己实现一个简易的服务器单线程即可。 DEMO 1
package com.artisan.bio;import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;/*** author 小工匠* version 1.0* mark: show me the code , change the world*/
public class Server {public static void main(String[] args) {// BIO 面向字节byte[] bytes new byte[1024];ServerSocket serverSocket null;try {serverSocket new ServerSocket(1234);System.out.println(服务端已开启端口);while (true) {System.out.println();System.out.println(服务端等待连接......);Socket socket serverSocket.accept();System.out.println(服务端已经收到连接请求);System.out.println(服务端等待数据.....);socket.getInputStream().read(bytes);System.out.println(服务端等已收到数据.....);String msg new String(bytes);System.out.println(接收到了数据: msg);}} catch (IOException e) {throw new RuntimeException(e);}}
} 创建了一个服务端类在类中实现实例化了一个SocketServer并绑定了1234端口。之后调用accept方法来接收连接请求并且调用read方法来接收客户端发送的数据。最后将接收到的数据打印。 package com.artisan.bio;import java.io.IOException;
import java.net.Socket; /*** author 小工匠* version 1.0* mark: show me the code , change the world*/
public class Client {public static void main(String[] args) throws IOException {Socket socket new Socket(127.0.0.1,1234);socket.getOutputStream().write(数据数据数据.getBytes());socket.close();}
} 客户端首先实例化Socket对象并且绑定ip为127.0.0.1本机端口号为1234调用write方法向服务器发送数据 运行测试会发现
在服务器启动后客户端还没有连接服务器时服务器由于调用了accept方法将一直阻塞直到有客户端请求连接服务器。 DEMO 2
客户端的逻辑主要是建立Socket – 连接服务器 – 发送数据我们的数据是在连接服务器之后就立即发送的现在我们来对客户端进行一次扩展当我们连接服务器后不立即发送数据而是等待控制台手动输入数据后再发送给服务端
客户端代码如下 try {Socket socket new Socket(127.0.0.1,1234);String message null;Scanner sc new Scanner(System.in);message sc.next();socket.getOutputStream().write(message.getBytes());socket.close();sc.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}小结论 从上面的运行结果中我们可以看到服务器端在启动后
1首先需要等待客户端的连接请求第一次阻塞
2如果没有客户端连接服务端将一直阻塞等待
3然后当客户端连接后服务器会等待客户端发送数据第二次阻塞
4如果客户端没有发送数据那么服务端将会一直阻塞等待客户端发送数据。 服务端从启动到收到客户端数据的这个过程将会有两次阻塞的过程
1第一次在等待连接时阻塞2第二次在等待数据时阻塞。
BIO会产生两次阻塞这就是BIO的非常重要的一个特点。 单线程BIO的缺陷
当我们的服务器接收到一个连接后并且没有接收到客户端发送的数据时是会阻塞在read()方法中的那么此时如果再来一个客户端的请求服务端是无法进行响应的。换言之在不考虑多线程的情况下BIO是无法处理多个客户端请求的 BIO如何处理并发
单线程版的BIO并不能处理多个客户端的请求那么如何能使BIO处理多个客户端请求呢?
我们只需要在每一个连接请求到来时创建一个线程去执行这个连接请求就可以在BIO中处理多个客户端请求了这也就是为什么BIO的其中一条概念是服务器实现模式为一个连接一个线程即客户端有连接请求时服务器端就需要启动一个线程进行处理。
【多线程BIO版本简易实现】 package com.artisan.bio;import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;/*** author 小工匠* version 1.0* mark: show me the code , change the world*/
public class ServerMultThread {public static void main(String[] args) {byte[] buffer new byte[1024];try {ServerSocket serverSocket new ServerSocket(1234);System.out.println(服务器已启动并监听8080端口);while (true) {System.out.println();System.out.println(服务器正在等待连接...);Socket socket serverSocket.accept();new Thread(() - {System.out.println(Thread.currentThread().getName() 服务器已接收到连接请求...);System.out.println();System.out.println(Thread.currentThread().getName() 服务器正在等待数据...);try {socket.getInputStream().read(buffer);} catch (IOException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() 服务器已经接收到数据);System.out.println();String content new String(buffer);System.out.println(Thread.currentThread().getName() 接收到的数据: content);}).start();}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}多启动几个客户端测试结果如下 多线程BIO服务器的弊端
多线程BIO服务器虽然解决了单线程BIO无法处理并发的弱点但是也带来一个问题如果有大量的请求连接到我们的服务器上但是却不发送消息那么我们的服务器也会为这些不发送消息的请求创建一个单独的线程那么如果连接数少还好连接数一多就会对服务端造成极大的压力。
所以如果这种不活跃的线程比较多我们应该采取单线程的一个解决方案但是单线程又无法处理并发这就陷入了一种很矛盾的状态于是就有了NIO NIO NIO要解决的问题
我们先来看看单线程模式下BIO服务器的代码其实NIO需要解决的最根本的问题就是存在于BIO中的两个阻塞分别是等待连接时的阻塞和等待数据时的阻塞
package com.artisan.bio;import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;/*** author 小工匠* version 1.0* mark: show me the code , change the world*/
public class Server {public static void main(String[] args) {// BIO 面向字节byte[] bytes new byte[1024];ServerSocket serverSocket null;try {serverSocket new ServerSocket(1234);System.out.println(服务端已开启端口);while (true) {System.out.println();System.out.println(服务端等待连接......);Socket socket serverSocket.accept();System.out.println(服务端已经收到连接请求);System.out.println(服务端等待数据.....);socket.getInputStream().read(bytes);System.out.println(服务端等已收到数据.....);String msg new String(bytes);System.out.println(接收到了数据: msg);}} catch (IOException e) {throw new RuntimeException(e);}}
}
如果单线程服务器在等待数据时阻塞那么第二个连接请求到来时服务器是无法响应的。如果是多线程服务器那么又会有为大量空闲请求产生新线程从而造成线程占用系统资源线程浪费的情况。
那么我们的问题就转移到如何让单线程服务器在等待客户端数据到来时依旧可以接收新的客户端连接请求。 模拟NIO
如果要解决上文中提到的单线程服务器接收数据时阻塞而无法接收新请求的问题那么其实可以让服务器在等待数据时不进入阻塞状态问题不就迎刃而解了吗
方案一 等待连接时和等待数据时不阻塞
package com.artisan.bio;/*** author 小工匠* version 1.0* mark: show me the code , change the world*/import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;public class MyServer {public static void main(String[] args) throws Exception {ByteBuffer byteBuffer ByteBuffer.allocate(1024);try {//Java为非阻塞设置的类ServerSocketChannel serverSocketChannel ServerSocketChannel.open();serverSocketChannel.bind(new InetSocketAddress(1234));//设置为非阻塞serverSocketChannel.configureBlocking(false);while (true) {SocketChannel socketChannel serverSocketChannel.accept();if (socketChannel null) {//表示没人连接System.out.println(Thread.currentThread().getName() 正在等待客户端请求连接...);Thread.sleep(5000);} else {System.out.println(Thread.currentThread().getName() 当前接收到客户端请求连接...);}if (socketChannel ! null) {//设置为非阻塞socketChannel.configureBlocking(false);byteBuffer.flip();//切换模式 写--读int effective socketChannel.read(byteBuffer);if (effective ! 0) {String content Charset.forName(utf-8).decode(byteBuffer).toString();System.out.println(content);} else {System.out.println(Thread.currentThread().getName() 当前未收到客户端消息);}}}} catch (IOException e) {e.printStackTrace();}}
}客户端测试代码
package com.artisan.bio;import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;/*** author 小工匠* version 1.0* mark: show me the code , change the world*/
public class ClientWithInput {private static Socket socket;private static Scanner sc;public static void main(String[] args) throws IOException {try {while (true) {socket new Socket(127.0.0.1, 1234);String message null;sc new Scanner(System.in);message sc.next();socket.getOutputStream().write(message.getBytes());}} catch (IOException e) {e.printStackTrace();} finally {socket.close();sc.close();}}
} 在这种解决方案下虽然在接收客户端消息时不会阻塞但是又开始重新接收服务器请求用户根本来不及输入消息服务器就转向接收别的客户端请求了换言之服务器弄丢了当前客户端的请求。 方案二缓存Socket轮询数据是否准备好
package com.artisan.bio;/*** author 小工匠* version 1.0* mark: show me the code , change the world*/import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;public class MyServer {public static void main(String[] args) throws Exception {ByteBuffer byteBuffer ByteBuffer.allocate(1024);ListSocketChannel socketList new ArrayListSocketChannel();try {//Java为非阻塞设置的类ServerSocketChannel serverSocketChannel ServerSocketChannel.open();serverSocketChannel.bind(new InetSocketAddress(1234));//设置为非阻塞serverSocketChannel.configureBlocking(false);while (true) {SocketChannel socketChannel serverSocketChannel.accept();if (socketChannel null) {//表示没人连接System.out.println(Thread.currentThread().getName() 正在等待客户端请求连接...);Thread.sleep(5000);} else {System.out.println(socketChannel.getRemoteAddress() 当前接收到客户端请求连接...);socketList.add(socketChannel);}for (SocketChannel socket : socketList) {socket.configureBlocking(false);int effective socket.read(byteBuffer);if (effective ! 0) {byteBuffer.flip();//切换模式 写--读String content Charset.forName(UTF-8).decode(byteBuffer).toString();System.out.println(socket.getRemoteAddress() 接收到消息: content);System.out.println();byteBuffer.clear();} else {// System.out.println(socket.getRemoteAddress() 当前未收到客户端消息);}}}} catch (IOException e) {e.printStackTrace();}}
}客户端我们使用如下代码去模拟
package com.artisan.bio;import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;/*** author 小工匠* version 1.0* mark: show me the code , change the world*/
public class ClientWithInput {private static Socket socket;private static Scanner sc;public static void main(String[] args) throws IOException {try {while (true) {socket new Socket(127.0.0.1, 1234);String message null;sc new Scanner(System.in);message sc.next();socket.getOutputStream().write(message.getBytes());}} catch (IOException e) {e.printStackTrace();} finally {socket.close();sc.close();}}
} 我们可以发现 1. 消息并没有丢失 2. server端并没有开启多线程来处理消息均是在main线程
在解决方案一中我们采用了非阻塞方式但是发现一旦非阻塞等待客户端发送消息时就不会再阻塞了而是直接重新去获取新客户端的连接请求这就会造成客户端连接丢失。
而在解决方案二中我们将连接存储在一个list集合中每次等待客户端消息时都去轮询看看消息是否准备好如果准备好则直接打印消息。
可以看到从头到尾我们一直没有开启第二个线程而是一直采用单线程来处理多个客户端的连接这样的一个模式可以很完美地解决BIO在单线程模式下无法处理多客户端请求的问题并且解决了非阻塞状态下连接丢失的问题。 方案二存在的问题
从刚才的运行结果中其实可以看出消息没有丢失程序也没有阻塞。
但是在接收消息的方式上可能有些许不妥我们采用了一个轮询的方式来接收消息每次都轮询所有的连接看消息是否准备好测试用例中只是三个连接所以看不出什么问题来但是我们假设有1000万连接甚至更多采用这种轮询的方式效率是极低的。
另外1000万连接中我们可能只会有100万会有消息剩下的900万并不会发送任何消息那么这些连接程序依旧要每次都去轮询这显然是不合适的。 NIO是如何解决这些问题的
在真实NIO中并不会在Java层上来进行一个轮询而是将轮询的这个步骤交给我们的操作系统来进行他将轮询的那部分代码改为操作系统级别的系统调用select函数在linux环境中为epoll在操作系统级别上调用select函数主动地去感知有数据的socket 使用select/poll/epoll和直接在应用层做轮询的区别
NIO使用了操作系统底层的轮询系统调用 select/epoll(windows:select,linux:epoll)那么为什么不直接实现而要去调用系统来做轮询呢 select底层逻辑
假设有A、B、C、D、E五个连接同时连接服务器那么根据我们上文中的设计程序将会遍历这五个连接轮询每个连接获取各自数据准备情况那么和我们自己写的程序有什么区别呢
首先我们写的Java程序其本质在轮询每个Socket的时候也需要去调用系统函数那么轮询一次调用一次会造成不必要的上下文切换开销。
而Select会将五个请求从用户态空间全量复制一份到内核态空间在内核态空间来判断每个请求是否准备好数据完全避免频繁的上下文切换。所以效率是比我们直接在应用层写轮询要高的。
如果select没有查询到到有数据的请求那么将会一直阻塞是的select是一个阻塞函数。如果有一个或者多个请求已经准备好数据了那么select将会先将有数据的文件描述符置位然后select返回。返回后通过遍历查看哪个请求有数据。 select的缺点
1底层存储依赖bitmap处理的请求是有上限的为10242文件描述符是会置位的所以如果当被置位的文件描述符需要重新使用时是需要重新赋空值的3fd文件描述符从用户态拷贝到内核态仍然有一笔开销4select返回后还要再次遍历来获知是哪一个请求有数据。 poll的底层逻辑
poll的工作原理和select很像先来看一段poll内部使用的一个结构体
struct pollfd{int fd;short events;short revents;
}poll同样会将所有的请求拷贝到内核态和select一样poll同样是一个阻塞函数当一个或多个请求有数据的时候也同样会进行置位但是它置位的是结构体pollfd中的events或者revents置位而不是对fd本身进行置位所以在下一次使用的时候不需要再进行重新赋空值的操作。 poll内部存储不依赖bitmap而是使用pollfd数组的这样一个数据结构数组的大小肯定是大于1024的。
解决了select 1、2两点的缺点。 epoll的底层逻辑
epoll是最新的一种多路IO复用的函数。这里只说说它的特点。 epoll和上述两个函数最大的不同是它的fd是共享在用户态和内核态之间的所以可以不必进行从用户态到内核态的一个拷贝这样可以节约系统资源。 另外在select和poll中如果某个请求的数据已经准备好它们会将所有的请求都返回供程序去遍历查看哪个请求存在数据但是epoll只会返回存在数据的请求这是因为epoll在发现某个请求存在数据时首先会进行一个重排操作将所有有数据的fd放到最前面的位置然后返回返回值为存在数据请求的个数N那么我们的上层程序就可以不必将所有请求都轮询而是直接遍历epoll返回的前N个请求这些请求都是有数据的请求。
高性能网络编程 - select、 poll 、epoll 、libevent BIO VS NIO Stream vs. Buffer
Java NIO和IO之间的第一个重要区别是IO是面向流的NIO是面向缓冲区的。那么这意味着什么 面向流的Java IO意味着你可以从流中一次读取一个或多个字节。你对读取的字节做什么取决于你。它们不会缓存在任何地方。此外你无法在流中的数据中前后移动。如果需要在从流中读取的数据中前后移动则需要先将其缓存在缓冲区中。 Java NIO的面向缓冲区的方法略有不同。数据被读入缓冲区稍后处理该缓冲区。你可以根据需要在缓冲区中前后移动。这使你在处理过程中具有更大的灵活性。但是你还需要检查缓冲区是否包含完整处理所需的所有数据。并且你需要确保在将更多数据读入缓冲区时不要覆盖尚未处理的缓冲区中的数据。 Blocking vs. Non-blocking Java IO的各种流都是blocking的。这意味着当线程调用read或write时该线程将被阻塞直到有一些数据要读取或者数据被完全写入在此期间该线程无法执行任何其他操作。 Java NIO的非阻塞模式允许线程请求从通道读取数据并且只获取当前可用的内容或者根本没有数据如果当前没有数据可用。线程可以继续使用其他内容而不是在数据可供读取之前保持阻塞状态。 非阻塞写入也是如此线程可以请求将某些数据写入通道但不要等待它完全写入。然后线程可以继续并在同一时间做其他事情 线程在IO调用中没有阻塞时花费空闲时间通常在此期间在其他通道上执行IO。也就是说单个线程现在可以管理多个输入和输出通道。 Selectors
Java NIO的选择器允许单个线程监视多个输入通道。你可以使用选择器注册多个通道然后使用单个线程“选择”具有可用于处理的输入的通道或者选择准备写入的通道。这种选择器机制使单个线程可以轻松管理多个通道。 NIO和经典IO如何影响应用程序的设计
选择NIO或IO作为IO工具包可能会影响应用程序设计的以下方面:
1API调用NIO或IO类 2处理数据 3用于处理数据的线程数。 API调用NIO或IO类
使用NIO时的API调用看起来与使用IO时不同。而不是仅仅从例如InputStream读取字节的数据字节必须首先将数据读入缓冲区然后从那里进行处理 数据处理
Java IO从阻塞流中读取数据
在IO设计中从InputStream或Reader中读取字节的数据字节
想象一下正在处理基于行的文本数据流。
例如
Name: Anna
Age: 25
Email: [urlmailto:annamailserver.com]annamailserver.com[/url]
Phone: 1234567890这个文本行流可以像这样处理
InputStream input ... ; // get the InputStream from the client socketBufferedReader reader new BufferedReader(new InputStreamReader(input));String nameLine reader.readLine();
String ageLine reader.readLine();
String emailLine reader.readLine();
String phoneLine reader.readLine();注意处理状态是如何由程序执行的程度决定的。换句话说一旦第一个reader.readLine方法返回我们就确定已经读取了整行文本。readLine会阻塞直到读取整行这就是原因。我们还知道此行包含名称。同样当第二个readLine调用返回时我们知道此行包含年龄等。
正如我们所看到的只有当有新数据要读取时程序才会进行并且对于每个步骤我们都知道该数据是什么。一旦执行的线程已经超过读取代码中的某个数据片段该线程就不会在数据中向后移动通常不会 Java NIO从通道读取数据直到所有需要的数据都在缓冲区中
NIO的实现看起来会有所不同这是一个简化的例子
ByteBuffer buffer ByteBuffer.allocate(48);
int bytesRead inChannel.read(buffer);注意第二行从通道读取字节到ByteBuffer。当该方法调用返回时您不知道所需的所有数据是否都在缓冲区内。你只知道缓冲区包含一些字节这使得处理更加困难。
想象一下在第一次读取缓冲调用之后是否所有读入缓冲区的内容都是半行。例如“姓名An”。你能处理这些数据吗并不是的。在完成任何数据的处理之前您需要等待至少一整行数据进入缓冲区。
那么你怎么知道缓冲区是否包含足够的数据来处理它好吧你没有。找出的唯一方法是查看缓冲区中的数据。结果是在您知道所有数据是否存在之前您可能需要多次检查缓冲区中的数据。这既低效又可能在程序设计方面变得混乱。
比如
ByteBuffer buffer ByteBuffer.allocate(48);int bytesRead inChannel.read(buffer);while(! bufferFull(bytesRead) ) {bytesRead inChannel.read(buffer);
}bufferFull方法必须跟踪读入缓冲区的数据量并返回true或false具体取决于缓冲区是否已满。换句话说如果缓冲区已准备好进行处理则认为它已满。
bufferFull方法扫描缓冲区但必须使缓冲区保持与调用bufferFull方法之前相同的状态。如果不是则可能无法在正确的位置读入读入缓冲区的下一个数据。这不是不可能的但这是另一个需要注意的问题。
如果缓冲区已满则可以对其进行处理。如果它不满您可能能够部分处理那里的任何数据如果这在您的特定情况下是有意义的。在许多情况下它没有。
这个图中说明了is-data-in-buffer-ready循环 适用场景
NIO允许您仅使用一个或几个线程来管理多个通道网络连接或文件但成本是解析数据可能比从阻塞流中读取数据时更复杂。
如果您需要同时管理数千个打开的连接每个只发送一些数据例如聊天服务器在NIO中实现服务器可能是一个优势。同样如果您需要与其他计算机保持大量开放连接例如在P2P网络中使用单个线程来管理所有出站连接可能是一个优势。 如果您拥有较少带宽的连接一次发送大量数据那么可能最经典的IO服务器实现可能是最合适的。 通俗解释
以众所周之的数据读取过程为例我们来一个更简化的理解。
对于数据读取就读取速度来说CPU 内存 硬盘。
I 就是从硬盘到内存O- 就是从内存到硬盘
第一种方式从硬盘读取数据然后程序一直等数据读完后继续你的操作。这种方式是最简单的叫阻塞IO也就是经典IO。
第二种方式从硬盘读取数据然后程序继续向下执行等数据读取完后通知当前程序读取完成对硬件来说叫中断对程序来说叫回调然后此程序可以立即处理读取的数据也可以执行完当前操作后再对读取完的数据进行操作。 文章转载自: http://www.morning.zstry.cn.gov.cn.zstry.cn http://www.morning.qjbxt.cn.gov.cn.qjbxt.cn http://www.morning.xnzmc.cn.gov.cn.xnzmc.cn http://www.morning.kysport1102.cn.gov.cn.kysport1102.cn http://www.morning.mcwrg.cn.gov.cn.mcwrg.cn http://www.morning.qbwmz.cn.gov.cn.qbwmz.cn http://www.morning.qrmry.cn.gov.cn.qrmry.cn http://www.morning.tqfnf.cn.gov.cn.tqfnf.cn http://www.morning.zympx.cn.gov.cn.zympx.cn http://www.morning.bpzw.cn.gov.cn.bpzw.cn http://www.morning.dbqg.cn.gov.cn.dbqg.cn http://www.morning.epeij.cn.gov.cn.epeij.cn http://www.morning.ntkpc.cn.gov.cn.ntkpc.cn http://www.morning.pjqxk.cn.gov.cn.pjqxk.cn http://www.morning.qrqdr.cn.gov.cn.qrqdr.cn http://www.morning.xqndf.cn.gov.cn.xqndf.cn http://www.morning.nfmtl.cn.gov.cn.nfmtl.cn http://www.morning.qkzdc.cn.gov.cn.qkzdc.cn http://www.morning.gswfs.cn.gov.cn.gswfs.cn http://www.morning.hylbz.cn.gov.cn.hylbz.cn http://www.morning.qjghx.cn.gov.cn.qjghx.cn http://www.morning.lgznc.cn.gov.cn.lgznc.cn http://www.morning.bfhfb.cn.gov.cn.bfhfb.cn http://www.morning.rwjh.cn.gov.cn.rwjh.cn http://www.morning.qtfss.cn.gov.cn.qtfss.cn http://www.morning.wrkcw.cn.gov.cn.wrkcw.cn http://www.morning.tqpr.cn.gov.cn.tqpr.cn http://www.morning.xrftt.cn.gov.cn.xrftt.cn http://www.morning.jfbgn.cn.gov.cn.jfbgn.cn http://www.morning.krgjc.cn.gov.cn.krgjc.cn http://www.morning.hrkth.cn.gov.cn.hrkth.cn http://www.morning.dfhkh.cn.gov.cn.dfhkh.cn http://www.morning.trzmb.cn.gov.cn.trzmb.cn http://www.morning.flxqm.cn.gov.cn.flxqm.cn http://www.morning.snnkt.cn.gov.cn.snnkt.cn http://www.morning.tlbhq.cn.gov.cn.tlbhq.cn http://www.morning.bswxt.cn.gov.cn.bswxt.cn http://www.morning.wjpsn.cn.gov.cn.wjpsn.cn http://www.morning.cykqb.cn.gov.cn.cykqb.cn http://www.morning.gjqgz.cn.gov.cn.gjqgz.cn http://www.morning.yhtnr.cn.gov.cn.yhtnr.cn http://www.morning.cctgww.cn.gov.cn.cctgww.cn http://www.morning.lrflh.cn.gov.cn.lrflh.cn http://www.morning.hsjrk.cn.gov.cn.hsjrk.cn http://www.morning.sftrt.cn.gov.cn.sftrt.cn http://www.morning.tyrlk.cn.gov.cn.tyrlk.cn http://www.morning.gxqpm.cn.gov.cn.gxqpm.cn http://www.morning.rkgyx.cn.gov.cn.rkgyx.cn http://www.morning.qsswb.cn.gov.cn.qsswb.cn http://www.morning.yrms.cn.gov.cn.yrms.cn http://www.morning.xlclj.cn.gov.cn.xlclj.cn http://www.morning.npcxk.cn.gov.cn.npcxk.cn http://www.morning.nkbfc.cn.gov.cn.nkbfc.cn http://www.morning.zyrp.cn.gov.cn.zyrp.cn http://www.morning.gfmpk.cn.gov.cn.gfmpk.cn http://www.morning.cqrenli.com.gov.cn.cqrenli.com http://www.morning.yjmns.cn.gov.cn.yjmns.cn http://www.morning.mzrqj.cn.gov.cn.mzrqj.cn http://www.morning.rzczl.cn.gov.cn.rzczl.cn http://www.morning.mplld.cn.gov.cn.mplld.cn http://www.morning.cpmfp.cn.gov.cn.cpmfp.cn http://www.morning.bxrqf.cn.gov.cn.bxrqf.cn http://www.morning.nlcw.cn.gov.cn.nlcw.cn http://www.morning.qpmwb.cn.gov.cn.qpmwb.cn http://www.morning.prjty.cn.gov.cn.prjty.cn http://www.morning.srgsb.cn.gov.cn.srgsb.cn http://www.morning.kdxzy.cn.gov.cn.kdxzy.cn http://www.morning.ctswj.cn.gov.cn.ctswj.cn http://www.morning.rkdw.cn.gov.cn.rkdw.cn http://www.morning.zsgbt.cn.gov.cn.zsgbt.cn http://www.morning.zynjt.cn.gov.cn.zynjt.cn http://www.morning.drywd.cn.gov.cn.drywd.cn http://www.morning.xnymt.cn.gov.cn.xnymt.cn http://www.morning.lhrcr.cn.gov.cn.lhrcr.cn http://www.morning.skksz.cn.gov.cn.skksz.cn http://www.morning.ywrt.cn.gov.cn.ywrt.cn http://www.morning.zwwhq.cn.gov.cn.zwwhq.cn http://www.morning.hbxnb.cn.gov.cn.hbxnb.cn http://www.morning.nnrqg.cn.gov.cn.nnrqg.cn http://www.morning.qzpsk.cn.gov.cn.qzpsk.cn