2.NIO

NIO和IO的區別:java

      IO是面向流的,NIO是面向緩衝區的。服務器

      Java IO的各類流是阻塞的。這意味着,當一個線程調用read() 或 write()時,該線程被阻塞,直到有一些 數        據被讀取,或數據徹底寫入。java NIO的非阻塞模式,使一個線程從某通道發送請求讀取數據,可是它              僅能獲得目前可用的數據,若是目前沒有數據可用時,就什麼都不會獲取,不是保持線程阻塞。
socket

    Java NIO的選擇器容許一個單獨的線程來監視多個輸入通道。測試

若是須要管理同時打開的成千上萬個鏈接,這些鏈接每次只是發送少許的數據,例如聊天服務器,實現NIO的服務器多是一個優點。this

服務端實例:spa

public class NIOServer {
//通道管理器
private Selector selector;
/* 得到一個ServerSocket通道,並對該通道作一些初始化的工做*/
    public void initServer(int port) throws IOException {
        // 得到一個ServerSocket通道
        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        // 設置通道爲非阻塞
        serverChannel.configureBlocking(false);
        // 將該通道對應的ServerSocket綁定到port端口
        serverChannel.socket().bind(new InetSocketAddress(port));
        // 得到一個通道管理器
        this.selector = Selector.open();
        //將通道管理器和該通道綁定,併爲該通道註冊SelectionKey.OP_ACCEPT事件,註冊該事件後,
        //當該事件到達時,selector.select()會返回,若是該事件沒到達selector.select()會一直阻塞。
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);
    }
/**
 * 採用輪詢的方式監聽selector上是否有須要處理的事件,若是有,則進行處理
 * @throws  IOException
 */
@SuppressWarnings("unchecked")
public void listen() throws IOException {
System.out.println("服務端啓動成功!");
// 輪詢訪問selector
while (true) {
//當註冊的事件到達時,方法返回;不然,該方法會一直阻塞
selector.select();
// 得到selector中選中的項的迭代器,選中的項爲註冊的事件
Iterator ite = this.selector.selectedKeys().iterator();
while (ite.hasNext()) {
SelectionKey key = (SelectionKey) ite.next();
// 刪除已選的key,以防重複處理
ite.remove();
// 客戶端請求鏈接事件
if (key.isAcceptable()) {
ServerSocketChannel server = (ServerSocketChannel) key
.channel();
// 得到和客戶端鏈接的通道
SocketChannel channel = server.accept();
// 設置成非阻塞
channel.configureBlocking(false);
//在這裏能夠給客戶端發送信息哦
channel.write(ByteBuffer.wrap(new String("向客戶端發送了一條信息").getBytes()));
//在和客戶端鏈接成功以後,爲了能夠接收到客戶端的信息,須要給通道設置讀的權限。
channel.register(this.selector, SelectionKey.OP_READ);
// 得到了可讀的事件
} else if (key.isReadable()) {
read(key);
}
}
}
}
/**
 * 處理讀取客戶端發來的信息 的事件
 * @param key
 * @throws IOException 
 */
public void read(SelectionKey key) throws IOException{
// 服務器可讀取消息:獲得事件發生的Socket通道
SocketChannel channel = (SocketChannel) key.channel();
// 建立讀取的緩衝區
ByteBuffer buffer = ByteBuffer.allocate(10);
channel.read(buffer);
byte[] data = buffer.array();
String msg = new String(data).trim();
System.out.println("服務端收到信息:"+msg);
ByteBuffer outBuffer = ByteBuffer.wrap(msg.getBytes());
channel.write(outBuffer);// 將消息回送給客戶端
}
/**
 * 啓動服務端測試
 * @throws IOException 
 */
public static void main(String[] args) throws IOException {
NIOServer server = new NIOServer();
server.initServer(8000);
server.listen();
}
}

客戶端實例.net

package com.ailk.fba.interfacefeel;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
 * NIO客戶端
 * @author 小路
 */
public class NIOClient {
	//通道管理器
	private Selector selector;

	/**
	 * 得到一個Socket通道,並對該通道作一些初始化的工做
	 * @param ip 鏈接的服務器的ip
	 * @param port  鏈接的服務器的端口號         
	 * @throws IOException
	 */
	public void initClient(String ip,int port) throws IOException {
		// 得到一個Socket通道
		SocketChannel channel = SocketChannel.open();
		// 設置通道爲非阻塞
		channel.configureBlocking(false);
		// 得到一個通道管理器
		this.selector = Selector.open();
		
		// 客戶端鏈接服務器,其實方法執行並無實現鏈接,須要在listen()方法中調
		//用channel.finishConnect();才能完成鏈接
		channel.connect(new InetSocketAddress(ip,port));
		//將通道管理器和該通道綁定,併爲該通道註冊SelectionKey.OP_CONNECT事件。
		channel.register(selector, SelectionKey.OP_CONNECT);
	}

	/**
	 * 採用輪詢的方式監聽selector上是否有須要處理的事件,若是有,則進行處理
	 * @throws IOException
	 */
	@SuppressWarnings("unchecked")
	public void listen() throws IOException {
		// 輪詢訪問selector
		while (true) {
			selector.select();
			// 得到selector中選中的項的迭代器
			Iterator ite = this.selector.selectedKeys().iterator();
			while (ite.hasNext()) {
				SelectionKey key = (SelectionKey) ite.next();
				// 刪除已選的key,以防重複處理
				ite.remove();
				// 鏈接事件發生
				if (key.isConnectable()) {
					SocketChannel channel = (SocketChannel) key
							.channel();
					// 若是正在鏈接,則完成鏈接
					if(channel.isConnectionPending()){
						channel.finishConnect();
						
					}
					// 設置成非阻塞
					channel.configureBlocking(false);

					//在這裏能夠給服務端發送信息哦
					channel.write(ByteBuffer.wrap(new String("向服務端發送了一條信息").getBytes()));
					//在和服務端鏈接成功以後,爲了能夠接收到服務端的信息,須要給通道設置讀的權限。
					channel.register(this.selector, SelectionKey.OP_READ);
					
					// 得到了可讀的事件
				} else if (key.isReadable()) {
						read(key);
				}

			}

		}
	}
	/**
	 * 處理讀取服務端發來的信息 的事件
	 * @param key
	 * @throws IOException 
	 */
	public void read(SelectionKey key) throws IOException{
		//和服務端的read方法同樣
	}
	
	
	/**
	 * 啓動客戶端測試
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		NIOClient client = new NIOClient();
		client.initClient("localhost",8000);
		client.listen();
	}

}
相關文章
相關標籤/搜索