`
yangyangmyself
  • 浏览: 229241 次
  • 性别: 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英文高清原版

    Java NIO英文高清原版

    java nio 包读取超大数据文件

    Java nio 超大数据文件 超大数据文件Java nio 超大数据文件 超大数据文件Java nio 超大数据文件 超大数据文件Java nio 超大数据文件 超大数据文件Java nio 超大数据文件 超大数据文件Java nio 超大数据文件 超大数据...

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

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

    java NIO 中文版

    讲解了 JavaIO 与 JAVA NIO区别,JAVA NIO设计理念,以及JDK中java NIO中语法的使用

    java nio 实现socket

    java nio 实现socketjava nio 实现socketjava nio 实现socketjava nio 实现socketjava nio 实现socket

    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 New IO 的简称,在 jdk1.4 里提供的新 api 。 Sun 官方标榜的特性如下: – 为所有的原始类型提供 (Buffer) 缓存支持。 – 字符集编码解码解决方案。 – Channel :一个新的原始 I/O 抽象。 – 支持...

    Java Nio selector例程

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

    java NIO.zip

    java NIO.zip

    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 读文件,java nio 读文件

    java NIO技巧及原理

    java NIO技巧及原理解析,java IO原理,NIO框架分析,性能比较

    JAVA NIO 学习资料

    JAVA NIO学习资料JAVA NIO学习资料

    Java NIO测试示例

    Java NIO测试示例

    基于Java NIO实现五子棋游戏.zip

    基于Java NIO实现五子棋游戏.zip基于Java NIO实现五子棋游戏.zip 基于Java NIO实现五子棋游戏.zip基于Java NIO实现五子棋游戏.zip 基于Java NIO实现五子棋游戏.zip基于Java NIO实现五子棋游戏.zip 基于Java NIO实现...

    JavaNIO.pdf

    JavaNIO.pdf

    Java NIO.pdf

    java nio编程 非阻塞模式的通信 电子书 带目录标签

    Java NIO 英文文字版

    Many serious Java programmers, especially enterprise Java programmers, consider the new I/O API--called NIO for New Input/Output--the most important feature in the 1.4 version of the Java 2 Standard ...

Global site tag (gtag.js) - Google Analytics