java NIO socket 通訊例項
阿新 • • 發佈:2019-02-16
java Nio 通訊與Bio通訊主要不同點:
1.Nio中的單個channel即可支援讀操作也可以支援寫操作,而bio中讀操作要用inputstream,寫操作要outputstream.
2.nio 採用byteBuffer 作為記憶體快取區,向channel裡寫或者度操作,bio基本是用byte[]
3.nio採用 selector元件輪詢讀取就緒channel
服務端demo程式碼:
package com.my.socket3; import java.io.ByteArrayOutputStream; 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.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Iterator; import java.util.Set; import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream; public class ServerTest { public static void main(String[] args) throws Exception { server(); } public static void server(){ ServerSocketChannel channel=null; try{ Selector selector=Selector.open(); channel=ServerSocketChannel.open(); channel.configureBlocking(false); channel.socket().setReuseAddress(true); channel.bind(new InetSocketAddress(8020)); channel.register(selector, SelectionKey.OP_ACCEPT,new Integer(1)); while(true){ if(selector.select()>0){ Set<SelectionKey> sets=selector.selectedKeys(); Iterator<SelectionKey> keys=sets.iterator(); while(keys.hasNext()){ SelectionKey key=keys.next(); keys.remove(); if(key.isAcceptable()){ key.attach(new Integer(1)); SocketChannel schannel=((ServerSocketChannel) key.channel()).accept(); schannel.configureBlocking(false); schannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE); } if(key.isReadable()){ SocketChannel schannel=(SocketChannel) key.channel(); ByteBuffer buf=ByteBuffer.allocate(1024); ByteOutputStream output=new ByteOutputStream(); int len=0; while((len=schannel.read(buf))!=0){ buf.flip(); byte by[]=new byte[buf.remaining()]; buf.get(by); output.write(by); buf.clear(); } String str=new String(output.getBytes()); key.attach(str); } if(key.isWritable()){ Object object=key.attachment(); String attach=object!=null ? "server replay: "+object.toString() : "server replay: "; SocketChannel schannel=(SocketChannel) key.channel(); schannel.write(ByteBuffer.wrap(attach.getBytes())); } } } } }catch(Exception e){ e.printStackTrace(); }finally{ if(channel!=null){ try { channel.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
客戶端demo程式碼
package com.my.socket3; import java.io.ByteArrayOutputStream; 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; import java.util.Set; public class ClientTest { public static void main(String[] args) throws Exception { client(); } public static void client() { SocketChannel channel=null; try { Selector selector=Selector.open(); channel = SocketChannel.open(); channel.configureBlocking(false); channel.connect(new InetSocketAddress(8020)); channel.register(selector, SelectionKey.OP_CONNECT); while(true){ if(selector.select()>0){ Iterator<SelectionKey> set=selector.selectedKeys().iterator(); while(set.hasNext()){ SelectionKey key=set.next(); set.remove(); SocketChannel ch=(SocketChannel) key.channel(); if(key.isConnectable()){ ch.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE,new Integer(1)); ch.finishConnect(); } if(key.isReadable()){ key.attach(new Integer(1)); ByteArrayOutputStream output=new ByteArrayOutputStream(); ByteBuffer buffer=ByteBuffer.allocate(1024); int len=0; while((len=ch.read(buffer))!=0){ buffer.flip(); byte by[]=new byte[buffer.remaining()]; buffer.get(by); output.write(by); buffer.clear(); } System.out.println(new String(output.toByteArray())); output.close(); } if(key.isWritable()){ key.attach(new Integer(1)); ch.write(ByteBuffer.wrap((("client say:hi")).getBytes())); } } } } } catch (Exception e) { e.printStackTrace(); }finally{ try { channel.close(); } catch (IOException e) { e.printStackTrace(); } } } static class ClientRunnable implements Runnable{ private SocketChannel ch; private ClientRunnable(SocketChannel ch){ this.ch=ch; } @Override public void run() { try { while(true){ ch.write(ByteBuffer.wrap((("client say:hi")).getBytes())); Thread.sleep(5000); } } catch (Exception e) { e.printStackTrace(); try { ch.close(); } catch (IOException e1) { e1.printStackTrace(); } } } } }
跑demo時遇到的問題
1.客戶端需要進行 ch.finishiCnonnect()操作,否則兩邊都阻塞著
2.讀channel中的bytebuffer時, while((len=ch.read(buffer))!=0) 判斷不要寫成while((len=ch.read(buffer))!=-1)
如果SocketChannel被設定為非阻塞,則它的read操作可能返回三個值:
1) 大於0,表示讀取到了位元組數;
2) 等於0,沒有讀取到訊息,可能TCP處於Keep-Alive狀態,接收到的是TCP握手訊息;
3) -1,連線已經被對方合法關閉。