非阻塞式Socket舉例

package NonBlockingSocket;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;

public class Server {// 這是服務端

	/**
	 * @param args
	 * @throws IOException
	 * 
	 * 非阻塞的Socked使用總結(服務器端): 一、涉及關鍵類: 1、ByteBuffer 2、SelectionKey 3、Selector
	 * 4、ServerSocketChannel 5、Iterator 6、SocketChannel 二、各類的綜合使用方法及相互聯繫
	 * 以下是使用前對各對象的設置: 1、得到ServerSocketChannel和Selector對象
	 * 2、設置ServerSocketChannel內部channel阻塞方式 3、把ServerSocketChannel綁定到指定地址的指定端口上
	 * 4、把ServerSocketChannel註冊給Selector對象,並選擇感興趣的動作 以下是使用過程:
	 * 1、使用Selector對象對指定地址指定端口的請求進行選擇,這裏的選擇只關注自己以前設置的感興趣的請求
	 * 2、從Selector對象裏得到感興趣的鏈接的Set,然後得到該Set對象的迭代器Iterator對象
	 * 3、如果該迭代器裏有元素,則依次使用next()取出,取出的元素可強轉爲SelectionKey,此SelectionKey對象至少包裝了兩個屬性:一個是該屬性是哪種類型的,另一個是一個SelectableChannel
	 * 如果此SelectedKey是OP_ACCEPT,那麼SelectableChannel可以強轉爲ServerSocketChannel對象,使這個對象accept()可以得到SocketChannel對象,同樣可以像註冊ServerSocketChannel
	 * 一樣註冊SocketChannel到Selector對像並選擇自己感興趣的動作。SelectionKey的isConnecttable()方法不適用於服務端。
	 * 4、可以從SocketChannel內read()和write()信息,這些信息必須包裝在ByteBuffer內
	 * 5、可以對ByteBuffer裏的內容做多種解釋,其中一種是人類比較容易理解的字符格式:CharBuffer,轉換方式有兩種:一種是ByteBuffer.asCharBuffer()這種轉換隻是改變了相同內容的不同解釋;
	 * 另一種是使用編碼: Charset tCs=Charset.forName("gb2312"); CharBuffer
	 * tCb=tCs.newDecoder().decode(tBb); 這種轉換是對相同語義做不同存儲。
	 * 6、經常將上述步驟放在一個大的循環內部,這樣可以不斷地檢查指定地址的指定端口的請求
	 */
	private final static int BUF_SIZE = 1024;

	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		Server s = new Server();
		s.startServer();
		while (true) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	//
	public Server() {
		// TODO Auto-generated constructor stub
		init();
	}

	ServerSocketChannel ssc;
	Selector sel;
	boolean start;

	//
	private void init() {
		// TODO Auto-generated method stub
		try {
			ssc = ServerSocketChannel.open();
			ssc.socket()
					.bind(
							new InetSocketAddress(InetAddress
									.getByAddress(new byte[] { (byte) 11,
											(byte) 11, (byte) 11, (byte) 11 }),
									1111));
			sel = Selector.open();
			ssc.configureBlocking(false);
			ssc.register(sel, SelectionKey.OP_ACCEPT);
			start = false;
			aid = 0;
			rid = 0;
			wid = 0;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private static int rid;
	private static int wid;
	private static int aid;

	//
	private void startServer() throws IOException {
		// TODO Auto-generated method stub
		start = true;
		Iterator<SelectionKey> iKey = null;
		SelectionKey skKey = null;
		System.out.println("Server started.");
		while (start) {
			sel.select();// 不要忘了
			iKey = sel.selectedKeys().iterator();
			if (iKey.hasNext()) {
				// System.out.println("Server=====>>>hasNext");
				skKey = iKey.next();
				iKey.remove();
				if (skKey.isAcceptable()) {
					aid++;
					ServerSocketChannel tSsc = (ServerSocketChannel) skKey
							.channel();
					SocketChannel tSc = tSsc.accept();
					tSc.configureBlocking(false);
					tSc.register(sel, SelectionKey.OP_READ
							| SelectionKey.OP_WRITE);
					System.out.println("The " + aid + "th accept.");
					continue;
				}
				if (skKey.isReadable()) {
					rid++;
					SocketChannel tSc = (SocketChannel) skKey.channel();
					tSc.configureBlocking(false);

					// ByteBuffer的創建方法之一:ByteBuffer.allocate(BUF_SIZE);
					ByteBuffer tBb = ByteBuffer.allocate(BUF_SIZE);

					tSc.read(tBb);
					tBb.flip();
					// 以下做解碼用:
					Charset tCs = Charset.forName("gb2312");
					CharBuffer tCb = tCs.newDecoder().decode(tBb);

					System.out.println(tCb);
					System.out.println("The " + rid + "th read.");
					continue;
				}
				if (skKey.isWritable()) {
					wid++;
					SocketChannel tSc = (SocketChannel) skKey.channel();
					tSc.configureBlocking(false);
					// CharBuffer tCb=ByteBuffer.wrap(("The "+wid+"th
					// response.").getBytes()).asCharBuffer();

					// ByteBuffer的創建方法之二:ByteBuffer.wrap(("The "+wid+"th
					// response.").getBytes())
					tSc.write(ByteBuffer.wrap(("The " + wid + "th response.")
							.getBytes()));

					System.out.println("The " + wid + "th write.");
					continue;
				}
			}
		}
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章