网络编程复习(三):NIO模式

来源:互联网 发布:神经网络算法能做什么 编辑:程序博客网 时间:2024/05/21 17:36

关于NIO,就是同步非阻塞,虽然效率会提高,但实现起来的有点麻烦,所以实际开发中用的很少,更多的是用Netty框架使用网络Socket,Netty其实是对JDK的nio的一个优化封装,实现起来更加方便,后续也将会介绍,下面看看流程图解:


client端:

package 网络编程_NIO;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.SocketChannel;public class Client {public static void main(String[] args) {//定义socket连接的地址与端口InetSocketAddress address = new InetSocketAddress("127.0.0.1",8888);//通道SocketChannel channel = null;//缓冲区ByteBuffer buffer = ByteBuffer.allocate(1024);try {//打开通道channel = SocketChannel.open();//连接地址channel.connect(address);while(true){byte[] bys = new byte[1024];//控制台读取数据1024字节System.in.read(bys);//数据放入缓冲区buffer.put(bys);//复位buffer.flip();//通道将缓冲区数据写给服务端channel.write(buffer);//清空缓冲区buffer.clear();}} catch (Exception e) {e.printStackTrace();}finally {if(channel!=null){try {channel.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}}

server端:

package 网络编程_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 Server implements Runnable{private Selector selector;private ByteBuffer readerBuffer = ByteBuffer.allocate(1024);//private ByteBuffer writerBuffer = ByteBuffer.allocate(1024);public  Server(int port) {try {//打开多路复用器this.selector = Selector.open();//打开连接通道ServerSocketChannel socketChannel = ServerSocketChannel.open();//设置为非阻塞模式socketChannel.configureBlocking(false);//通道绑定端口监听socketChannel.bind(new InetSocketAddress(port));//通道注册到多路复用器上socketChannel.register(this.selector, SelectionKey.OP_ACCEPT);System.out.println("Server started..."+port);} catch (Exception e) {// TODO: handle exception}}@Overridepublic void run() {while(true){try {//多路复用器开始监听this.selector.select();//返回多路复用器选择的结果集Iterator<SelectionKey> keys = this.selector.selectedKeys().iterator();//开始遍历while(keys.hasNext()){//获得选择的第一个元素SelectionKey key = keys.next();//将选择的元素从容器中移除keys.remove();//如果元素可用if(key.isValid()){//如果为阻塞状态if(key.isAcceptable()){this.accept(key);}//可读if(key.isReadable()){this.read(key);}//可写if(key.isWritable()){this.writer(key);}}}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}private void writer(SelectionKey key) {/*this.writerBuffer.clear();SocketChannel channel  = (SocketChannel) key.channel();byte[] bys = new String("服务端已经接受到你的数据").getBytes();writerBuffer.put(bys);writerBuffer.flip();try {channel.write(writerBuffer);writerBuffer.clear();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}*/}private void read(SelectionKey key) {try {this.readerBuffer.clear();SocketChannel channel = (SocketChannel) key.channel();int count = channel.read(readerBuffer);if(count == -1){key.channel().close();key.cancel();return;}this.readerBuffer.flip();byte[] bys = new byte[this.readerBuffer.remaining()];this.readerBuffer.get(bys);String body = new String(bys).trim();System.out.println("Server"+body);//channel.register(this.selector, SelectionKey.OP_WRITE);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}private void accept(SelectionKey key) {try {ServerSocketChannel socketChannel = (ServerSocketChannel) key.channel();SocketChannel channel = socketChannel.accept();channel.configureBlocking(false);//阻塞状态变为可读状态channel.register(this.selector, SelectionKey.OP_READ);} catch (Exception e) {// TODO: handle exception}}public static void main(String[] args) {new Thread(new Server(8888)).start();}}

这里我并没有实现服务端向客户端写数据,因为这种情况客户端也像一个服务端了,实现起来和server端代码很相似,加一个Selector就行了,这里感觉很麻烦,所以没有实现,有兴趣的朋友可以试下。