java nio过程

1、服务端:ServerSocketChannel进行监听,注册SelectionKey.OP_ACCEPT事件,服务器阻塞在selector.select()方法中,等待客户端连接。
2、客户端:SocketChannel创建连接,调用socketChannel.connect(SERVER_ADDRESS)连接服务器(此时服务器之前阻塞在selector.select()往下走,进入selectionKey.isAcceptable()逻辑,通过ServerSocketChannel的accept方法获得客户端SocketChannel,SocketChannel注册 SelectionKey.OP_READ事件,等待客户端输入流,此时又阻塞在selector.select()方法),客户端进入selectionKey.isConnectable(),如果client.isConnectionPending()==true,通过 client.finishConnect()强制连接,然后准备数据,通过client.write(sendbuffer)向服务器发送数据,此时,服务器之前阻塞在selector.select()往下走,进入selectionKey.isReadable()逻辑,通过缓冲区读取客户端输入流,然后调用client.register(selector, SelectionKey.OP_WRITE)注册写客户端流事件,进入selectionKey.isWritable()逻辑,准备写客户端的数据,通过client.write(sendbuffer)方法写给客户端,客户端之前write之后,会进行注册SelectionKey.OP_READ,等待服务器响应,阻塞在selector.select()中,由于这个时候服务器有了返回,就不阻塞了,进入selectionKey.isReadable()逻辑,得到服务器返回,如果需要再次发送数据给服务器,则注册write事件。刚才服务器write给客户端之后,如果想继续收到客户端数据,需要注册client.register(selector, SelectionKey.OP_READ)读事件,等待客户端再一次写入数据,阻塞在selector.select()方法

 

服务端:

package com.rb.socket.nio.server.n;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
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;

public class NIOServer {

	/*标识数字*/
	private int flag = 0;

	/*缓冲区大小*/
	private int BLOCK = 4096;

	/*接受数据缓冲区*/
	private ByteBuffer sendbuffer = ByteBuffer.allocate(BLOCK);

	/*发送数据缓冲区*/
	private ByteBuffer receivebuffer = ByteBuffer.allocate(BLOCK);

	private Selector selector;

	public NIOServer(int port) throws IOException {
		// 打开服务器套接字通道   
		ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
		// 服务器配置为非阻塞   
		serverSocketChannel.configureBlocking(false);
		// 检索与此通道关联的服务器套接字   
		ServerSocket serverSocket = serverSocketChannel.socket();
		// 进行服务的绑定   
		serverSocket.bind(new InetSocketAddress(port));
		// 通过open()方法找到Selector   
		selector = Selector.open();
		// 注册到selector,等待连接   
		serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
		System.out.println("Server Start----:" + port);
	}

	// 监听   
	private void listen() throws IOException {
		while (true) {
			// 选择一组键,并且相应的通道已经打开   
			selector.select();
			// 返回此选择器的已选择键集。   
			Set<SelectionKey> selectionKeys = selector.selectedKeys();
			Iterator<SelectionKey> iterator = selectionKeys.iterator();
			while (iterator.hasNext()) {
				SelectionKey selectionKey = iterator.next();
				iterator.remove();
				handleKey(selectionKey);
			}
		}
	}

	// 处理请求   
	private void handleKey(SelectionKey selectionKey) throws IOException {
		// 接受请求   
		ServerSocketChannel server = null;
		SocketChannel client = null;
		String receiveText;
		String sendText;
		int count = 0;
		// 测试此键的通道是否已准备好接受新的套接字连接。   
		if (selectionKey.isAcceptable()) {
			// 返回为之创建此键的通道。   
			server = (ServerSocketChannel) selectionKey.channel();
			// 接受到此通道套接字的连接。   
			// 此方法返回的套接字通道(如果有)将处于阻塞模式。   
			client = server.accept();
			// 配置为非阻塞   
			client.configureBlocking(false);
			// 注册到selector,等待连接   
			client.register(selector, SelectionKey.OP_READ);
		} else if (selectionKey.isReadable()) {
			// 返回为之创建此键的通道。   
			client = (SocketChannel) selectionKey.channel();
			//将缓冲区清空以备下次读取   
			receivebuffer.clear();
			//读取服务器发送来的数据到缓冲区中   
			count = client.read(receivebuffer);
			if (count > 0) {
				receiveText = new String(receivebuffer.array(), 0, count);
				System.out.println("服务器端接受客户端数据--:" + receiveText);
				client.register(selector, SelectionKey.OP_WRITE);
			}
		} else if (selectionKey.isWritable()) {
			//将缓冲区清空以备下次写入   
			sendbuffer.clear();
			// 返回为之创建此键的通道。   
			client = (SocketChannel) selectionKey.channel();
			sendText = "message from server--" + flag++;
			//向缓冲区中输入数据   
			sendbuffer.put(sendText.getBytes());
			//将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位   
			sendbuffer.flip();
			//输出到通道   
			client.write(sendbuffer);
			System.out.println("服务器端向客户端发送数据--:" + sendText);
			client.register(selector, SelectionKey.OP_READ);
		}
	}

	/**  
	 * @param args  
	 * @throws IOException  
	 */
	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub   
		int port = 8011;
		NIOServer server = new NIOServer(port);
		server.listen();
	}
}

 

客户端:

package com.rb.socket.nio.server.n;
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 NIOClient {   
  
    /*标识数字*/  
    private static int flag = 0;   
    /*缓冲区大小*/  
    private static int BLOCK = 4096;   
    /*接受数据缓冲区*/  
    private static ByteBuffer sendbuffer = ByteBuffer.allocate(BLOCK);   
    /*发送数据缓冲区*/  
    private static ByteBuffer receivebuffer = ByteBuffer.allocate(BLOCK);   
    /*服务器端地址*/  
    private final static InetSocketAddress SERVER_ADDRESS = new InetSocketAddress(   
            "localhost", 8011);   
  
    public static void main(String[] args) throws IOException {   
        // TODO Auto-generated method stub   
        // 打开socket通道   
        SocketChannel socketChannel = SocketChannel.open();   
        // 设置为非阻塞方式   
        socketChannel.configureBlocking(false);   
        // 打开选择器   
        Selector selector = Selector.open();   
        // 注册连接服务端socket动作   
        socketChannel.register(selector, SelectionKey.OP_CONNECT);   
        // 连接   
        socketChannel.connect(SERVER_ADDRESS);   
        // 分配缓冲区大小内存   
           
        Set<SelectionKey> selectionKeys;   
        Iterator<SelectionKey> iterator;   
        SelectionKey selectionKey;   
        SocketChannel client;   
        String receiveText;   
        String sendText;   
        int count=0;   
  
        while (true) {   
            //选择一组键,其相应的通道已为 I/O 操作准备就绪。   
            //此方法执行处于阻塞模式的选择操作。   
            selector.select();   
            //返回此选择器的已选择键集。   
            selectionKeys = selector.selectedKeys();   
            //System.out.println(selectionKeys.size());   
            iterator = selectionKeys.iterator();   
            while (iterator.hasNext()) {   
                selectionKey = iterator.next();   
                if (selectionKey.isConnectable()) {   
                    System.out.println("client connect");   
                    client = (SocketChannel) selectionKey.channel();   
                    // 判断此通道上是否正在进行连接操作。   
                    // 完成套接字通道的连接过程。   
                    if (client.isConnectionPending()) {   
                        client.finishConnect();   
                        System.out.println("完成连接!");   
                        sendbuffer.clear();   
                        sendbuffer.put("Hello,Server".getBytes());   
                        sendbuffer.flip();   
                        client.write(sendbuffer);   
                    }   
                    client.register(selector, SelectionKey.OP_READ);   
                } else if (selectionKey.isReadable()) {   
                    client = (SocketChannel) selectionKey.channel();   
                    //将缓冲区清空以备下次读取   
                    receivebuffer.clear();   
                    //读取服务器发送来的数据到缓冲区中   
                    count=client.read(receivebuffer);   
                    if(count>0){   
                        receiveText = new String( receivebuffer.array(),0,count);   
                        System.out.println("客户端接受服务器端数据--:"+receiveText);   
                        client.register(selector, SelectionKey.OP_WRITE);   
                    }   
  
                } else if (selectionKey.isWritable()) {   
                    sendbuffer.clear();   
                    client = (SocketChannel) selectionKey.channel();   
                    sendText = "message from client--" + (flag++);   
                    sendbuffer.put(sendText.getBytes());   
                     //将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位   
                    sendbuffer.flip();   
                    client.write(sendbuffer);   
                    System.out.println("客户端向服务器端发送数据--:"+sendText);   
                    client.register(selector, SelectionKey.OP_READ);   
                }   
            }   
            selectionKeys.clear();   
        }   
    }   
}  

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值