注意:
1.NIO主要用于服務端,若用來客戶端相對于它帶來的額外復雜性有點不值得。
2.用于編碼解碼字符集請根據您的機器缺省字符集進行調整,如GB2312,GBK,UTF-8,UTF-16等,若出現亂碼請更換之。
3.BufferSize請根據您可能發送接收的最大字符串長度進行相應調整。
代碼:
package com.heyang.biz.server.test.nio;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
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;
/**
* NIO 服務器
* 說明:
* 作者:何楊(heyang78@gmail.com)
* 創建時間:2011-1-3 下午12:09:02
* 修改時間:2011-1-3 下午12:09:02
*/
public class NIOServer{
// 本地字符集
private static final String LocalCharsetName = "gb2312";
// 本地服務器監聽的端口
private static final int Listenning_Port=8888;
// 緩沖區大小
private static final int Buffer_Size=1024;
// 超時時間,單位毫秒
private static final int TimeOut=3000;
public static void main(String[] args) throws Exception{
// 創建一個在本地端口進行監聽的服務Socket信道.并設置為非阻塞方式
ServerSocketChannel serverChannel=ServerSocketChannel.open();
serverChannel.socket().bind(new InetSocketAddress(Listenning_Port));
serverChannel.configureBlocking(false);
// 創建一個選擇器并將serverChannel注冊到它上面
Selector selector=Selector.open();
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
while(true){
// 等待某個信道就緒
if(selector.select(TimeOut)==0){
System.out.println(".");
continue;
}
// 獲得就緒信道的鍵迭代器
Iterator<SelectionKey> keyIter=selector.selectedKeys().iterator();
// 使用迭代器進行遍歷就緒信道
while(keyIter.hasNext()){
SelectionKey key=keyIter.next();
// 這種情況是有客戶端連接過來,準備一個clientChannel與之通信
if(key.isAcceptable()){
SocketChannel clientChannel=((ServerSocketChannel)key.channel()).accept();
clientChannel.configureBlocking(false);
clientChannel.register(key.selector(), SelectionKey.OP_READ,ByteBuffer.allocate(Buffer_Size));
}
// 客戶端有寫入時
if(key.isReadable()){
// 獲得與客戶端通信的信道
SocketChannel clientChannel=(SocketChannel)key.channel();
// 得到并重置緩沖區的主要索引值
ByteBuffer buffer=(ByteBuffer)key.attachment();
buffer.clear();
// 讀取信息獲得讀取的字節數
long bytesRead=clientChannel.read(buffer);
if(bytesRead==-1){
// 沒有讀取到內容的情況
clientChannel.close();
}
else{
// 將緩沖區準備為數據傳出狀態
buffer.flip();
// 將獲得字節字符串(使用Charset進行解碼)
String receivedString=Charset.forName(LocalCharsetName).newDecoder().decode(buffer).toString();
// 控制臺打印出來
System.out.println("接收到信息:"+receivedString);
// 準備發送的文本
String sendString="你好,客戶端. 已經收到你的信息"+receivedString;
// 將要發送的字符串編碼(使用Charset進行編碼)后再進行包裝
buffer=ByteBuffer.wrap(sendString.getBytes(LocalCharsetName));
// 發送回去
clientChannel.write(buffer);
// 設置為下一次讀取或是寫入做準備
key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);
}
}
keyIter.remove();
}
}
}
}
與之配合的客戶端代碼,沒有采用NIO方式。
package com.heyang.biz.server.test.nio;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
public class TestClient{
public static void main(String[] args) throws Exception{
Socket s=new Socket("127.0.0.1",8888);
InputStream inStram=s.getInputStream();
OutputStream outStream=s.getOutputStream();
// 輸出
PrintWriter out=new PrintWriter(outStream,true);
out.print("getPublicKey你好!");
out.flush();
s.shutdownOutput();// 輸出結束
// 輸入
Scanner in=new Scanner(inStram);
StringBuilder sb=new StringBuilder();
while(in.hasNextLine()){
String line=in.nextLine();
sb.append(line);
}
String response=sb.toString();
System.out.println("response="+response);
}
}
服務器端的輸出:
.
接收到信息:getPublicKey你好!
.
客戶端的輸出:
response=你好,客戶端. 已經收到你的信息getPublicKey你好!