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("[email protected]#$%")) {//收到关闭指令,发送确认关闭的指令给客户端,结束自身通道
			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,需要关闭客户端
	 *
	 * "[email protected]#$%"	->			"[email protected]#$%"                               约定好的内容("[email protected]#$%")
	 *
	 * "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("[email protected]#$%".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();
		}
	}
}

  客户端可开启多个,用于连接服务器端,亲测可用,有问题联系作者,[email protected]

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

时间: 2024-11-02 20:46:47

Java NIO初试的相关文章

Java NIO (五) 管道 (Pipe)

Java NIO 管道是2个线程之间的单向数据连接.Pipe有一个source通道和一个sink通道.数据会被写到sink通道,从source通道读取. 如下图: 向管道写数据: 从管道读数据: 1. 从读取管道的数据,需要访问source通道. 2. 调用source通道的read()方法来读取数据

Java NIO中的缓冲区Buffer(一)缓冲区基础

什么是缓冲区(Buffer) 定义 简单地说就是一块存储区域,哈哈哈,可能太简单了,或者可以换种说法,从代码的角度来讲(可以查看JDK中Buffer.ByteBuffer.DoubleBuffer等的源码),Buffer类内部其实就是一个基本数据类型的数组,以及对这个缓冲数组的各种操作: 常见的缓冲区如ByteBuffer.IntBuffer.DoubleBuffer...内部对应的数组依次是byte.int.double... 与通道的关系 在Java NIO中,缓冲区主要是跟通道(Chann

Java NIO通信框架在电信领域的实践

Java NIO通信框架在电信领域的实践 此文配图有错,华为电信软件V1版逻辑架构图与华为电信软件V2 MVC版逻辑架构图两张配图是同一张啊 另:我觉得作者在本文中遇到由于同步io引起的历史遗留问题更多的是架构的问题,在作架构时就需要考虑到同步io引起的阻塞问题,我觉得比较好的解决方案是使用排队的方式来下发请求,而不是每次下发请求都启一个线程,这样如果对方还是响应慢的话即使是用nio也是解决不了问题的.

java nio

NIO 是java nonblocking(非阻塞) IO 的简称,在jdk1.4 里提供的新api .Sun 官方标榜的特性如下: 为所有的原始类型提供(Buffer)缓存支持.字符集编码解码解决方案. Channel :一个新的原始I/O 抽象. 支持锁和内存映射文件的文件访问接口. 提供多路(non-bloking) 非阻塞式的高伸缩性网络I/O . Java NIO非堵塞应用通常适用用在I/O读写等方面,我们知道,系统运行的性能瓶颈通常在I/O读写,包括对端口和文件的操作上,之前,在打开

JAVA NIO 内存映射(转载)

原文地址:http://blog.csdn.net/fcbayernmunchen/article/details/8635427 Java类库中的NIO包相对于IO 包来说有一个新功能是内存映射文件,日常编程中并不是经常用到,但是在处理大文件时是比较理想的提高效率的手段.本文我主要想结合操作系统中(OS)相关方面的知识介绍一下原理. 在传统的文件IO操作中,我们都是调用操作系统提供的底层标准IO系统调用函数 read().write() ,此时调用此函数的进程(在JAVA中即java进程)由当

java nio 大白话描述(一)

java nio基本上常用的组件,selector,channel,buffer.这三个,其他的可以用到的时候再去参考就可以了. 看一本书的时候,基本看前三章或者四章基础知识,剩下的,实际生产中用到了再去看就可以. 大白话解释这三个重要的单词 Channel: Java的nio中,channel其实是用于传输的,也可以说是管道,是一个工具,可以对比一下io中的流,很类似.但是io中的流都是单向的,但是channel通道是双向的,就是这个通道里既可以读,也可以往里面写.这个channel跟buff

Java NIO -- 管道 (Pipe)

Java NIO 管道是2个线程之间的单向数据连接. Pipe有一个source通道和一个sink通道.数据会被写到sink通道,从source通道读取. 举个例子: package com.soyoungboy.nio; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.Pipe; import org.junit.Test; public class TestPipe { @Tes

Java NIO(六) Selector

Selector(选择器)是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件.这样,一个单独的线程可以管理多个channel,从而管理多个网络连接. 下面是本文所涉及到的主题列表: 为什么使用Selector? Selector的创建 向Selector注册通道 SelectionKey 通过Selector选择通道 wakeUp() close() 完整的示例 为什么使用Selector? 仅用单个线程来处理多个Channels的好处是,只需要更少的

Linux IO模型与Java NIO

概述看Java NIO一篇文章的时候又看到了"异步非阻塞"这个概念,一直处于似懂非懂的状态,想解释下到底什么是异步 什么是非阻塞,感觉抓不住重点.决定仔细研究一下.本文试图研究以下问题: web server原理,bio的connector与nio的connector在架构上到底什么区别? NIO的优势到底在哪里,是如何应用到实践中的? 同步/异步.阻塞/非阻塞到底是什么概念,引出的IO模型同步阻塞.同步非阻塞.异步阻塞.异步非阻塞的具体使用场景,适用的场景是怎样的? bio nio也