• Java NIO初试


    Java的NIO采用selector来轮循,还是不错,小试牛刀,下附代码

    Server:

    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 NIOServer {
    	private Selector selector;
    
    	public void initServer(int port) throws IOException {
    		ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();// 打开服务器套接字通道
    		serverSocketChannel.configureBlocking(false);// 设置为非阻塞模式
    		serverSocketChannel.socket().bind(new InetSocketAddress(port));// 绑定端口
    		this.selector = Selector.open();// 打开选择器
    		// 注册事件,当事件到达,selector。select()会返回,如果没有事件会一直阻塞
    		serverSocketChannel.register(this.selector, SelectionKey.OP_ACCEPT);// 注册选择器,接受客户端连接
    	}
    
    	public void listen() throws IOException {
    		System.out.println("服务器启动!开始轮询监听消息");
    		while (true) {
    			int ready = this.selector.select();
    			if (ready == 0) {
    				continue;
    			}
    			Iterator items = this.selector.selectedKeys().iterator();
    			while (items.hasNext()) {
    				SelectionKey key = (SelectionKey) items.next();
    				// 删除已经选择的key,防止重复处理
    				items.remove();
    				// 请求连接
    				if (key.isAcceptable()) {
    					ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key
    							.channel();
    					if (serverSocketChannel == null) {
    						continue;
    					}
    					SocketChannel socketChannel = serverSocketChannel.accept();//每次接受新的连接请求会产生新的通道,
    					socketChannel.configureBlocking(false);
    					socketChannel.write(ByteBuffer.wrap(new String(
    							"你好,客户端,连接已建立,可以开始通信!").getBytes()));//连接成功,发消息给客户端
    					System.out.println("连接已经建立");
    					socketChannel.register(this.selector, SelectionKey.OP_READ);//准备好接收数据
    				} else if (key.isReadable()) {
    					this.read(key);
    				}
    			}
    		}
    	}
    
    	public void read(SelectionKey key) throws IOException {
    		SocketChannel socketChannel = (SocketChannel) key.channel();
    		ByteBuffer byteBuffer = ByteBuffer.allocate(100);
    		socketChannel.read(byteBuffer);
    		byte[] data = byteBuffer.array();
    		String msg = new String(data).trim();
    		if (msg.equals("close~!@#$%")) {//收到关闭指令,发送确认关闭的指令给客户端,结束自身通道
    			ByteBuffer sendBuffer = ByteBuffer.wrap(new String("bye close").getBytes());
    			while (sendBuffer.hasRemaining()) {
    				socketChannel.write(sendBuffer);
    			}
    			socketChannel.close();
    			System.out.println("已经关闭");
    		} else {
    			System.out.println("server Receive:" + msg);//服务器收到任何消息都会给客户端发送"收到"
    			socketChannel.write(ByteBuffer.wrap(new String("收到!").getBytes()));
    		}
    	}
    
    	public static void main(String[] args) {
    		NIOServer server = new NIOServer();
    		try {
    			server.initServer(1377);
    			server.listen();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    }
    

      Client:

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    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;
    
    public class NIOClient {
    	private Selector selector;
    	//初始化
    	public void initClient(String ipAddress, int port) throws IOException {
    		SocketChannel socketChannel = SocketChannel.open();//打开套接字通道
    		socketChannel.configureBlocking(false);//非阻塞
    		this.selector = Selector.open();//打开选择器
    		socketChannel.connect(new InetSocketAddress(ipAddress, port));//指定ip地址和端口号用于连接
    		socketChannel.register(this.selector, SelectionKey.OP_CONNECT);//通道注册到选择器中,用于连接
    	}
    	//监听
    	public void listen() throws IOException {
    		while (true) {
    			//当客户端关闭的时候需要结束轮循的动作,这样程序才会结束
    			if (!this.selector.isOpen()) {
    				return;
    			}
    			int ready = this.selector.select();//这个才是真正的轮循啦,得到通道
    			if (ready == 0) {
    				continue;//如果selector中没有SocketChannel,直接开始下一次咯 
    			}
    			Iterator items = this.selector.selectedKeys().iterator();
    			while (items.hasNext()) {
    				SelectionKey key = (SelectionKey) items.next();
    				items.remove();//防止重复处理
    				if (key.isConnectable()) {//连接
    					System.out.println("正在连接,连接成功后,服务器会返回结果!");
    					SocketChannel socketChannel = (SocketChannel) key.channel();
    					// 如果正在连接,则完成连接
    					if (socketChannel.isConnectionPending()) {
    						socketChannel.finishConnect();
    					}
    					socketChannel.register(this.selector, SelectionKey.OP_READ);//重新注册该通道,用于读取数据
    				} else if (key.isReadable()) {//读取
    					this.read(key);
    				}
    			}
    		}
    	}
    
    	/****************************************************/
    	/*
    	 * 客户端关闭思路
    	 * 客户端							服务器
    	 * 
    	 * 用户输入bye,需要关闭客户端
    	 * 
    	 * "close~!@#$%"	->			"close~!@#$%"                               约定好的内容("close~!@#$%")
    	 * 					
    	 * "bye close"	<-				"bye close"     ----->服务器通道关闭        				约定好的内容("bye close")
    	 * 
    	 * 客户端通道关闭					服务器还可以接受别的请求
    	 * 
    	 */
    	public void read(SelectionKey key) throws IOException {
    		SocketChannel socketChannel = (SocketChannel) key.channel();
    		ByteBuffer receiveBuffer = ByteBuffer.allocate(100);
    		socketChannel.read(receiveBuffer);
    		byte[] data = receiveBuffer.array();
    		String msg = new String(data).trim();
    		if (msg.equals("bye close")) {//客户端和服务器约定关闭,收到服务器响应后可以关闭
    			System.out.println("关闭");
    			socketChannel.close();
    			this.selector.close();
    			return;
    		}
    		System.out.println("client receive:" + msg);
    		BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
    		String readMsg = reader.readLine();
    		ByteBuffer sendBuffer = ByteBuffer.allocate(256);
    		sendBuffer.clear();
    		if(readMsg.equals("bye")){//告诉服务器,准备要撤退,当服务器返回bye close,关闭通道和选择器
    			System.out.println("准备关闭");
    			sendBuffer.put("close~!@#$%".getBytes());
    			sendBuffer.flip();
    		}else{
    			sendBuffer.put(readMsg.getBytes());
    			sendBuffer.flip();
    		}
    		while (sendBuffer.hasRemaining()) {
    			socketChannel.write(sendBuffer);
    		}
    	}
    
    	public static void main(String[] args) {
    		NIOClient client = new NIOClient();
    		try {
    			client.initClient("127.0.0.1", 1377);
    			client.listen();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    }
    

      客户端可开启多个,用于连接服务器端,亲测可用,有问题联系作者,xusong1313@qq.com

    业务逻辑可自己完善,其实建议的搭建不难

  • 相关阅读:
    使用SELECT语句检索数据
    redis的安装和使用【2】redis的java操作
    Python之数据结构改造
    InnoDB undo log物理结构的初始化
    Redis-RDB持久化设置
    MySql(四)Select条件查询
    Node.js TLS/SSL
    Node.js 定时器
    Node.js 系统
    Node.js 字符串解码器
  • 原文地址:https://www.cnblogs.com/weiki/p/4465958.html
Copyright © 2020-2023  润新知