Java Nio相对原来io包而言,这里面对流处理有了大大的改进, 传统的io中的方法 如read、write、accept等都是线程阻塞的,新的类库在这方面有了大的增强,下面两个类分别为底层socket通讯的Server和Client端
Server端代码如下:
package nokia.nio; 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; public class ServerConnect { private static final int BUF_SIZE = 1024; private static final int PORT = 8080; private static final int TIMEOUT = 3000; public static void main(String[] args){ selector(); } public static void handleAccept(SelectionKey key) throws IOException{ ServerSocketChannel ssc = (ServerSocketChannel)key.channel(); SocketChannel sc = ssc.accept(); sc.configureBlocking(false); sc.register(key.selector(),SelectionKey.OP_READ, ByteBuffer.allocateDirect(BUF_SIZE)); } public static void handleRead(SelectionKey key) throws IOException{ SocketChannel sc = (SocketChannel)key.channel(); ByteBuffer buf = (ByteBuffer)key.attachment(); int bytesread = sc.read(buf); while(bytesread>0){ buf.flip(); while(buf.hasRemaining()){ System.out.print((char)buf.get()); } System.out.println(); buf.clear(); bytesread = sc.read(buf); } if(bytesread == -1){ sc.close(); } } public static void handleWrite(SelectionKey key) throws IOException{ ByteBuffer buf = (ByteBuffer)key.attachment(); buf.flip(); SocketChannel sc = (SocketChannel)key.channel(); while(buf.hasRemaining()){ sc.write(buf); } buf.compact(); } public static void selector(){ Selector selector = null; ServerSocketChannel ssc = null; try { selector = Selector.open(); ssc = ServerSocketChannel.open(); ssc.socket().bind(new InetSocketAddress(PORT)); ssc.configureBlocking(false); ssc.register(selector, SelectionKey.OP_ACCEPT); while(true){ if(selector.select(TIMEOUT)==0){ continue; } Iterator<SelectionKey> ite = selector.selectedKeys().iterator(); while(ite.hasNext()){ SelectionKey key = ite.next(); if(key.isAcceptable()){ handleAccept(key); } if(key.isReadable()){ handleRead(key); } if(key.isWritable() && key.isValid()){ handleWrite(key); } if(key.isConnectable()){ System.out.println("isConnectable = true"); } ite.remove(); } } }catch (IOException e){ e.printStackTrace(); }finally { try { if(selector != null){ selector.close(); } if(ssc != null){ ssc.close(); } }catch (IOException e){ e.printStackTrace(); } } } }
客户端代码如下:
package nokia.nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.sql.Time;
import java.util.concurrent.TimeUnit;
public class Client {
private static final int PORT = 8080;
public static void main(String[] args){
ByteBuffer buffer = ByteBuffer.allocate(1024);
SocketChannel socketChannel = null;
try {
socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress(PORT));
if(socketChannel.finishConnect()){
int i = 0;
while(true){
TimeUnit.SECONDS.sleep(1);
String info = "I am "+(i++)+"-th information from client";
buffer.clear();
buffer.put(info.getBytes());
buffer.flip();
while(buffer.hasRemaining()){
System.out.println(buffer);
socketChannel.write(buffer);
}
}
}
}catch (IOException e){
e.printStackTrace();
}catch(InterruptedException e){
e.printStackTrace();
}finally {
try {
if(socketChannel!=null){
socketChannel.close();
}
}catch (IOException e){
e.printStackTrace();
}
}
}
}
通过使用Selector、ServerSocketChannel、SocketChannel 以及他们感兴趣的事件 可以很高效的进行socket通讯
需要特别注意的是:
针对客户端 读就绪 代表此时 客户端收到了服务端发送过来的消息
写就绪 代表此时 服务端收到了客户端发送过来的消息
加入服务端和客户端在注册给选择器的时候都对写感兴趣,这个时候 一旦通道空闲 均会写就绪 这点特别注意