結合具體的Java Socket編程討論使用NIO提高服務端程序的性能的問題
Java NIO增加了新的SocketChannelServerSocketChannel等類來提供對構建高性能的服務端程序的支持 SocketChannelServerSocketChannel能夠在非阻塞的模式下工作它們都是selectable的類在構建服務器或者中間件時推薦使用Java NIO
在傳統的網絡編程中我們通常使用一個專用線程(Thread)來處理一個Socket連接通過使用NIO一個或者很少幾個Socket線程就可以處理成千上萬個活動的Socket連接
通常情況下通過ServerSocketChannelopen()獲得一個ServerSocketChannel的實例通過SocketChannelopen或者serverSocketChannelaccept()獲得一個SocketChannel實例要使ServerSocketChannel或者SocketChannel在非阻塞的模式下操作可以調用
sernfigureBlocking (false);
或者
nfigureBlocking (false);
語句來達到目的通常情況下服務端可以使用非阻塞的ServerSocketChannel這樣服務端的程序就可以更容易地同時處理多個socket線程
下面我們來看一個綜合例子這個例子使用了ServerSocketChannelSocketChannel開發了一個非阻塞的能處理多線程的Echo服務端程序見示例
【程序源代碼】
// ==================== Program Discription =====================
// 程序名稱示例 : SocketChannelDemojava
// 程序目的學習Java NIO#SocketChannel
// ==============================================================
import javanioByteBuffer;
import javaniochannelsServerSocketChannel;
import javaniochannelsSocketChannel;
import javaniochannelsSelector;
import javaniochannelsSelectionKey;
import javaniochannelsSelectableChannel;
import Socket;
import ServerSocket;
import InetSocketAddress;
import javautilIterator;
public class SocketChannelDemo
{
public static int PORT_NUMBER = ;//監聽端口
ServerSocketChannel serverChannel;
ServerSocket serverSocket ;
Selector selector ;
private ByteBuffer buffer = ByteBufferallocateDirect ();
public static void main (String [] args)
throws Exception
{
SocketChannelDemo server=new SocketChannelDemo();
serverinit(args);
serverstartWork();
}
public void init (String [] argv)throws Exception
{
int port = PORT_NUMBER;
if (argvlength > ) {
port = IntegerparseInt (argv []);
}
Systemoutprintln (Listening on port + port);
// 分配一個ServerSocketChannel
serverChannel = ServerSocketChannelopen();
// 從ServerSocketChannel裡獲得一個對應的Socket
serverSocket = serverChannelsocket();
// 生成一個Selector
selector = Selectoropen();
// 把Socket綁定到端口上
serverSocketbind (new InetSocketAddress (port));
//serverChannel為非bolck
nfigureBlocking (false);
// 通過Selector注冊ServerSocetChannel
serverChannelregister (selector SelectionKeyOP_ACCEPT);
}
public void startWork()throws Exception
{
while (true) {
int n = selectorselect();//獲得IO准備就緒的channel數量
if (n == ) {
continue; // 沒有channel准備就緒繼續執行
}
// 用一個iterator返回Selector的selectedkeys
Iterator it = selectorselectedKeys(erator();
// 處理每一個SelectionKey
while (ithasNext()) {
SelectionKey key = (SelectionKey) itnext();
// 判斷是否有新的連接到達
if (keyisAcceptable()) {
//返回SelectionKey的ServerSocketChannel
ServerSocketChannel server =
(ServerSocketChannel) keychannel();
SocketChannel channel = serveraccept();
registerChannel (selector channel
SelectionKeyOP_READ);
doWork (channel);
}
// 判斷是否有數據在此channel裡需要讀取
if (keyisReadable()) {
processData (key);
}
//刪除 selectedkeys
itremove();
}
}
}
protected void registerChannel (Selector selector
SelectableChannel channel int ops)
throws Exception
{
if (channel == null) {
return;
}
nfigureBlocking (false);
channelregister (selector ops);
}
//處理接收的數據
protected void processData (SelectionKey key)
throws Exception
{
SocketChannel socketChannel = (SocketChannel) keychannel();
int count;
bufferclear(); // 清空buffer
// 讀取所有的數據
while ((count = socketChannelread (buffer)) > ) {
bufferflip();
// send the data don′t assume it goes all at once
while (bufferhasRemaining())
{
//如果收到回車鍵則在返回的字符前增加[echo]$字樣
if(bufferget()==(char))
{
bufferclear();
bufferput([echo]___FCKpd___quot;getBytes());
bufferflip();
}
socketChannelwrite (buffer);//在Socket裡寫數據
}
bufferclear(); // 清空buffer
}
if (count < ) {
// count<說明已經讀取完畢
socketChannelclose();
}
}
private void doWork (SocketChannel channel)throws Exception
{
bufferclear();
bufferput (
HelloI am workingplease input some thingand i will echo to you!
[echo]
___FCKpd___quot;getBytes());
bufferflip();
channelwrite (buffer);
}
}
使用運行此程序然後在控制台輸入命令telnet localhost
From:http://tw.wingwit.com/Article/program/Java/hx/201311/26518.html