`
yangyangmyself
  • 浏览: 232416 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

JAVA NIO 之三

    博客分类:
  • Java
阅读更多
引用

   本节采用JDK1.5之后java.util.concurrent包的API服务端实现线程池读取信息,可以接采用Executors工具快速创建线程池,也可以ExecutorService子类自定义创建。
   客端连接服务端发送信息后关闭连接SOCKET短连接(HTTP为短连接),若采用SOCKET长连接,需要增加"心跳检测",本节暂未实现长连接。
  因Selector轮询可读事件时,存在重读问题,解决办法是在读的代码块中加下述代码selectKey.cancel()或selectKey.interestOps(selectKey.interestOps() & (~SelectionKey.OP_READ))

import java.io.IOException;
import java.net.InetSocketAddress;
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.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 服务端
*/
public class SocketServer {

	/**
	 * 服务器默认绑定端口
	 */
	public static final int DEFAULT_PORT = 9999;

	/**
	 * 选择器
	 */
	private Selector selector;
	/**
	 * 读取线程池
	 */
	private ExecutorService pool;
	
	public SocketServer(String ip, int port) {
		ServerSocketChannel ssc = null;
		try {
			int _port = DEFAULT_PORT;
			if (port > 0)
				_port = port;
			/* 获取通道 */
			ssc = ServerSocketChannel.open();
			/* 配置非阻塞 */
			ssc.configureBlocking(false);
			/**
			 * 配置绑定端口 ServerSocketChannel没有bind()方法,
			 * 因此有必要取出对等的ServerSocket并使用它来绑定到一
			 * 个端口以开始监听连接
			 */
			ssc.socket().bind(new InetSocketAddress(ip, _port));
			/* 获取选择器 */
			this.selector = Selector.open();
			/* 将通道注册到选择器 */
			ssc.register(this.selector, SelectionKey.OP_ACCEPT);
			
			/**
			 * 可以使用Executors,快速创建线程池,但是如果综合考虑
			 * CPU、内存等资及并发情况,可以采用自定方式创建池(
			 *  拒绝处理等问题
			 * ),此处简单自定义创建读取池
			 * */
			pool = new ThreadPoolExecutor(1, 2, 2000L,
					TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(5));
		} catch (IOException e2) {
			System.out.println("服务器启动失败!");
			e2.printStackTrace();
			try {
				if(ssc != null) ssc.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 轮询选择器
	 * @throws Exception
	 */
	public void pollSelect() throws Exception {
		/* (阻塞)轮询选择器,直到有事件 */
		while (true) {
			int readyChannels = 0;
			/*选择器是否关闭*/
			if(this.selector.isOpen()){
				readyChannels = this.selector.select();
			}
			if(readyChannels == 0) continue;
			/* 获取事件通知列表 */
			Iterator<SelectionKey> it = this.selector.selectedKeys().iterator();
			while (it.hasNext()) {
				SelectionKey selectKey = it.next();
				it.remove();
				try {
					process(selectKey);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 事件处理
	 * @param selectKey
	 */
	public void process(SelectionKey selectKey) throws Exception{
		/* 客户端连接事件 */
		if (selectKey.isAcceptable()) { 
			accept(selectKey);
		} else if (selectKey.isReadable()) { /* 可读事件 */
			read(selectKey);
			/**
			 * 解决重复读
			 * 或设置不关注读事件来解决重复
			 * selectKey.interestOps(selectKey.interestOps() & (~SelectionKey.OP_READ));
			 * */
			selectKey.cancel();
		}
	}
	
	/**
	 * 连接事件
	 * @param selectKey
	 */
	public void accept(SelectionKey selectKey) throws Exception {
		SocketChannel sc = null;
		try {
			ServerSocketChannel ssc = (ServerSocketChannel) selectKey
					.channel();
			sc = ssc.accept();
			sc.configureBlocking(false);
			System.out.println("客户端:"
                    + sc.socket().getInetAddress().getHostAddress()+"端口"+sc.socket().getPort()
                    + " 已连接");
			sc.register(this.selector, SelectionKey.OP_READ);
		} catch (Exception e) {
			if(sc!=null) 
				sc.close();
			throw new IOException("客户端已断开连接!");
		}
	}
	
	/**
	 * 可读事件
	 * @param selectKey
	 */
	public void read(SelectionKey selectKey) throws Exception{
		SocketChannel sc = (SocketChannel) selectKey
				.channel();
        /*提交线程池处理*/
		pool.submit(new SocketServerReadThread(sc));
	}
	
	
	public static void main(String[] args) {
		SocketServer ss = null;
		try {
			ss = new SocketServer("localhost", 9999);
			ss.pollSelect();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}


import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

/**
 * 从线程中读信息
 * @author oy
 *
 */
public class SocketServerReadThread implements Runnable{
	
	private SocketChannel channel;
	
	public SocketServerReadThread(SocketChannel channel){
		this.channel = channel;
	}
	
	@Override
	public void run() {
		try {
			// 创建读取的缓冲区
			ByteBuffer buffer = ByteBuffer.allocate(1024);
			channel.read(buffer);
			byte[] data = buffer.array();
			ByteArrayInputStream bais = new ByteArrayInputStream(data);
			ObjectInputStream ois = new ObjectInputStream(bais);
			User user = (User)ois.readObject();
			System.out.println("客户端:"
                    + channel.socket().getInetAddress().getHostAddress()+"端口"+channel.socket().getPort() + " 消息: " + user.toString());
		} catch (Exception e) {
			System.out.println("客户端已断开连接!");
			try {
				if(channel != null) 
					channel.close();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}
	}
}

0
0
分享到:
评论

相关推荐

    java NIO和java并发编程的书籍

    java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java...

    JavaNIO chm帮助文档

    Java NIO系列教程(三) Buffer Java NIO系列教程(四) Scatter/Gather Java NIO系列教程(五) 通道之间的数据传输 Java NIO系列教程(六) Selector Java NIO系列教程(七) FileChannel Java NIO系列教程(八) ...

    java NIO.zip

    通道是NIO中的核心概念之一,它提供了从一个数据源(如文件、套接字)到另一个数据源的数据传输路径。Java NIO支持多种类型的通道,包括文件通道(FileChannel)、套接字通道(SocketChannel)和服务器套接字通道...

    Java NIO英文高清原版

    Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java平台中用于替代标准I/O(BIO)模型的一种新机制。NIO在Java 1.4版本引入,提供了更高效的数据处理和通道通信方式,特别适用于高并发、大数据...

    Java NIO 中文 Java NIO 中文 Java NIO 中文文档

    Java NIO 深入探讨了 1.4 版的 I/O 新特性,并告诉您如何使用这些特性来极大地提升您所写的 Java 代码的执行效率。这本小册子就程序员所面临的有代表性的 I/O 问题作了详尽阐述,并讲解了 如何才能充分利用新的 I/O ...

    java NIO 视频教程

    Java NIO(New IO)是一个可以替代标准Java IO API的IO API(从Java 1.4开始),Java NIO提供了与标准IO不同的IO工作方式。 Java NIO: Channels and Buffers(通道和缓冲区) 标准的IO基于字节流和字符流进行操作的,...

    java nio 包读取超大数据文件

    #### 三、使用Java NIO读取超大数据文件 在Java NIO中,处理超大数据文件的关键在于合理利用内存映射文件(Memory-Mapped Files)来提高读取效率。内存映射文件是一种将文件内容直接映射到内存中的技术,使得对文件...

    java NIO技巧及原理

    Java NIO(New Input/Output)是Java标准库提供的一种I/O模型,它与传统的 Blocking I/O(IO)相比,提供了更加高效的数据传输方式。在Java NIO中,"新"主要体现在非阻塞和多路复用这两个特性上,这使得NIO更适合于...

    java NIO实例

    Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java从1.4版本开始引入的一种新的I/O模型,它为Java应用程序提供了更高效的数据传输方式。传统的Java I/O模型(BIO)在处理大量并发连接时效率较...

    一个java NIO的例子

    3. **选择器(Selector)**:选择器是Java NIO的核心,它可以监视多个通道的事件(如连接就绪、数据到达等)。通过注册感兴趣的事件类型到选择器,一个线程可以轮询选择器,找出已经准备好的通道并进行处理,避免了...

    Java NIO Socket基本

    Java NIO(New Input/Output)是Java标准库中提供的一种I/O模型,与传统的 Blocking I/O(同步阻塞I/O)相对。NIO在Java 1.4版本引入,其设计目标是提供一种更高效、更灵活的I/O操作方式,特别适合处理大量并发连接...

    Java Nio selector例程

    java侧起server(NioUdpServer1.java),基于Java Nio的selector 阻塞等候,一个android app(NioUdpClient1文件夹)和一个java程序(UI.java)作为两个client分别向该server发数据,server收到后分别打印收到的消息...

    java nio 实现socket

    **NIO非阻塞模式**:相比之下,NIO采用了非阻塞模式,即当没有数据可读时,`read()`方法不会阻塞,而是立即返回。这意味着应用程序可以同时处理多个输入/输出操作,而不需要为每个操作分配一个独立的线程。这样的...

    java基于NIO实现Reactor模型源码.zip

    java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现...

    Java NIO测试示例

    Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java从1.4版本开始引入的一种新的I/O模型,它为Java应用程序提供了更高效、灵活的I/O操作方式。NIO与传统的 Blocking I/O(阻塞I/O)模式相比,...

Global site tag (gtag.js) - Google Analytics