java 阻塞 socket_java socket非阻塞I/O
1????? 非阻塞(Nonblocking)體系結構
在這一部分,我將從理論的角度來解釋非阻塞體系的結構及其工作原理。這部“喜劇”(當然,如果你喜歡的話也可以稱做戲劇)的“人物”如下:
●服務器端:接收請求的應用程序。
●客戶端:向服務器端發出請求的應用程序。
●套接字通道:客戶端與服務器端之間的通信通道。它能識別服務器端的IP地址和端口號。數據以Buffer中元素的形式通過套接字通道傳送。
●選擇器:所有非阻塞技術的主要對象。它監視著已注冊的套接字通道,并序列化服務器需要應答的請求。
●關鍵字:選擇器用來對對象的請求進行排序。每個關鍵字代表一個單獨的客戶端子請求并包含識別客戶端和請求類型的信息。
2 SocketChannel 類
SocketAddress rama = new SocketAddress("localhost" , 8888) ;
利用靜態工廠方法得到SocketChannel的實例。
SocketChannel client = SocketChannel.open(rama) ;
如果這是傳統的套接字,那么就會尋求得到socket的輸入或者輸出流,利用通道,我們可以直接寫入通道本身,
不是寫入字節數組,而是要寫入ByteBuffer對象,將此對象寫入 client的read 方法。
客戶端應用程序同時執行對服務器端的請求,接著選擇器將其集中起來,創建關鍵字,然后將其發
送至服務器端。這看起來像是阻塞(Blocking)體系,因為在一定時間內只處理一個請求,但事實并非如此。
實際上,每個關鍵字不代表從客戶端發至服務器端的整個信息流,僅僅只是一部分。我們不要忘了選擇器能
分割那些被關鍵字標識的子請求里的數據。因此,如果有更多連續地數據發送至服務器端,那么選擇器就會
創建更多的根據時間共享策略(Time-sharing policy)來進行處理的關鍵字。強調一下,在圖一中關鍵字的顏色
與客戶端的顏色相對應。
服務器端非阻塞(Server Nonblocking)
客戶端和服務器端是兩個Java應用程序。套接字通道是SocketChannel類的實例,這個類允許通過網絡傳送數據。
它們能被Java程序員看作是一個新的套接字。SocketChannel類被定義在java.nio.channel包中。
選擇器是一個Selector類的對象。該類的每個實例均能監視更多的套接字通道,進而建立更多的連接。
當一些有意義的事發生在通道上(如客戶端試圖連接服務器端或進行讀/寫操作),選擇器便會通知應用程序處理請求。
選擇器會創建一個關鍵字,這個關鍵字是SelectionKey類的一個實例。每個關鍵字都保存著應用程序的標識及請求的類型。
其中,請求的類型可以是如下之一:
基本上,服務器端的實現是由選擇器等待事件和創建關鍵字的無限循環組成的。根據關鍵字的類型,及時的執行操作。
關鍵字存在以下4種可能的類型。
Acceptable: 相應的客戶端要求連接。
Connectable:服務器端接受連接。
Readable:服務器端可讀。
Writeable:服務器端可寫。
一個通用的實現非阻塞服務器的算法如下:
create SocketChannel;
create Selector
associate the SocketChannel to the Selector
for(;;) {
waiting events from the Selector;
event arrived; create keys;
for each key created by Selector {
check the type of request;
isAcceptable:
get the client SocketChannel;
associate that SocketChannel to the Selector;
record it for read/write operations
continue;
isReadable:
get the client SocketChannel;
read from the socket;
continue;
isWriteable:
get the client SocketChannel;
write on the socket;
continue;
}
}
3 ?下面為一個實例
(1)客戶端
1
packagecn.bupt.channel;23importjava.io.IOException;4importjava.net.InetSocketAddress;5importjava.net.SocketAddress;6importjava.nio.ByteBuffer;7importjava.nio.channels.Channels;8importjava.nio.channels.SocketChannel;9importjava.nio.channels.WritableByteChannel;1011importcn.bupt.constant.Default;1213
publicclassChargenClient{1415publicstaticintDEFAULT_PORT=8778;16
/**?*//**17?????*@paramargs18*/19
publicstaticvoidmain(String[]?args){20//TODO?Auto-generated?method?stub21if(args.length==0)22
{23???????????System.out.println("please?input?the?port");24return;25???????}2627intport?;282930???????port=DEFAULT_PORT?;3132???????SocketAddress?address=newInetSocketAddress(args[0]?,?port)?;33
try{34????????SocketChannel?client=SocketChannel.open(address)?;35????????ByteBuffer?buffer=ByteBuffer.allocate(74)?;36????????WritableByteChannel?out=Channels.newChannel(System.out)?;3738while(client.read(buffer)!=-1)39
{40????????????buffer.flip()?;41????????????out.write(buffer)?;42????????????buffer.clear()?;4344????????}45464748495051
????}catch(IOException?e){52//TODO?Auto-generated?catch?block53e.printStackTrace();54????}55565758????}5960}61
(2) 服務器端
1
packagecn.bupt.channel;23importjava.io.IOException;4importjava.net.InetSocketAddress;5importjava.net.ServerSocket;6importjava.nio.ByteBuffer;7importjava.nio.channels.SelectionKey;8importjava.nio.channels.Selector;9importjava.nio.channels.ServerSocketChannel;10importjava.nio.channels.SocketChannel;11importjava.util.Iterator;12importjava.util.Set;1314
publicclassChargenServer{1516publicstaticfinalintDEFAULT_PORT=8778;17
/**?*//**18?????*@paramargs19*/20
publicstaticvoidmain(String[]?args){21//TODO?Auto-generated?method?stub22intport?;23????????port=DEFAULT_PORT?;2425byte[]?rotation=newbyte[95*2]?;26for(bytei='';?i
{28????????????rotation[i-'']=i?;29????????????rotation[i+95-'']=i?;30????????}3132????????ServerSocketChannel?serverChannel=null;33????????Selector?selector=null;343536
/**?*//**37?????????*?先建立服務器端的通道38?????????*39*/4041
try{42????????????serverChannel=ServerSocketChannel.open()?;43????????????ServerSocket?ss=serverChannel.socket()?;44????????????InetSocketAddress?address=newInetSocketAddress(port)?;45????????????ss.bind(address)?;46????????????serverChannel.configureBlocking(false)?;47????????????selector=Selector.open()?;48????????????serverChannel.register(selector,?SelectionKey.OP_ACCEPT)?;49505152
????????}catch(IOException?e){53//TODO?Auto-generated?catch?block54e.printStackTrace();55????????}565758while(true)59
{6061
try{62????????????????selector.select()?;63
????????????}catch(IOException?e){64????????????????e.printStackTrace();65????????????}6667????????????Set?readyKeys=selector.selectedKeys()?;68????????????Iterator?iter=readyKeys.iterator()?;69while(iter.hasNext())70
{71????????????????SelectionKey?key=(SelectionKey)?iter.next()?;72????????????????iter.remove()?;7374if(key.isAcceptable())75
{76????????????????????ServerSocketChannel?server=(ServerSocketChannel)?key.channel()?;77
try{78????????????????????????SocketChannel?client=server.accept()?;79????????????????????????System.out.println("Accept?connection?from"+client)?;80????????????????????????client.configureBlocking(false)?;81????????????????????????SelectionKey?key2=client.register(selector,?SelectionKey.OP_WRITE)?;82????????????????????????ByteBuffer?buffer=ByteBuffer.allocate(74)?;83????????????????????????buffer.put(rotation?,0,72)?;84????????????????????????buffer.put((byte)'\r')?;85????????????????????????buffer.put((byte)'\n')?;86????????????????????????buffer.flip()?;87????????????????????????key2.attach(buffer)?;8889909192
????????????????????}catch(IOException?e){93//TODO?Auto-generated?catch?block94e.printStackTrace();95????????????????????}96979899100????????????????}101102else103if(key.isWritable())104
{105106
/**?*//**107?????????????????????????*?建立客戶端通道108?????????????????????????*109*/110????????????????????????SocketChannel?client=(SocketChannel)key.channel()?;111????????????????????????ByteBuffer?buffer=(ByteBuffer)?key.attachment()?;112if(!buffer.hasRemaining())113
{114????????????????????????????buffer.rewind()?;115intfirst=buffer.get()?;116????????????????????????????buffer.rewind()?;117intposition=first-''+1;118????????????????????????????buffer.put(rotation?,?position?,72)?;119????????????????????????????buffer.put((byte)'\r')?;120????????????????????????????buffer.put((byte)'\n');121????????????????????????????buffer.flip()?;122????????????????????????}123
try{124????????????????????????????client.write(buffer)?;125
????????????????????????}catch(IOException?e){126//TODO?Auto-generated?catch?block127e.printStackTrace();128????????????????????????}129????????????????????}130131132133134135136137138????????????????key.cancel()?;139
try{140????????????????????key.channel().close()?;141
????????????????}catch(IOException?e){142//TODO?Auto-generated?catch?block143e.printStackTrace();144????????????????}145????????????}146147148????????}149150151152153154155156157158????}159160}161
posted on 2010-08-01 21:19 buptduming 閱讀(4114) 評論(0) ?編輯 ?收藏
總結
以上是生活随笔為你收集整理的java 阻塞 socket_java socket非阻塞I/O的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: select 1 from table
- 下一篇: CListCtrl的用法总结