今天突然间想用nio实现个Echo服务,程序实现起来实现不算困难,但跑起来后,在Server端的ServerSocket完成accept之后,我的CPU总是跳到100%。嗯,小郁闷,后来,才发现自己在Server端注册了多余的监听事件SelectionKey.OP_WRITE,改过来后好多了,希望记住这个教训。
EchoServer.java
package edu.dlut.zxf.nio;
import java.io.IOException;
import java.net.InetAddress;
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.Set;
/**
* Echo服务器
* @author finux
*/
public class EchoServer {
public final static int BUFFER_SIZE = 1024; //默认端口
public final static String HOST = "210.30.107.17";
public final static int PORT = 8888;
public static void main(String[] args) {
ServerSocketChannel ssc = null;
//缓冲区
ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
Selector selector = null;
try {
selector = Selector.open();
ssc = ServerSocketChannel.open();
ssc.socket().bind(new InetSocketAddress(InetAddress.getByName(HOST), PORT));
ssc.configureBlocking(false);
ssc.register(selector, SelectionKey.OP_ACCEPT);
print("服务器启动,准备好连接...");
while (selector.select() > 0) {
Set<SelectionKey> selectionKeys = selector.selectedKeys();
for (SelectionKey key: selectionKeys) {
if (key.isAcceptable()) {
SocketChannel sc = ssc.accept();
print("有新的连接!地址:" + sc.socket().getRemoteSocketAddress());
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ);
// 不要写成:
// sc.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
// 毕竟这样多注册的无用的事件SelectionKey.OP_WRTE
// 如果是这样,在完成accept后,CPU也许会跑到100%
}
//same to if ((ops & SelectionKey.OP_READ) == SelectionKey.OP_READ) {
if (key.isReadable()) {
SocketChannel sc = (SocketChannel)key.channel();
print("有新的读取!地址:" + sc.socket().getRemoteSocketAddress());
buffer.clear();
sc.read(buffer);
buffer.flip();
byte[] b = new byte[buffer.limit()];
buffer.get(b);
String s = new String(b);
if (s.equals("bye")) {
print("断开连接:" + sc.socket().getRemoteSocketAddress());
//断开连接后,取消此键的通道到其选择器的注册
key.cancel();
sc.close();
continue;
}
print("读取的内容为:" + s);
buffer.clear();
s = "echo: " + s;
buffer.put(s.getBytes());
buffer.flip();
sc.write(buffer);
}
}
selectionKeys.clear();
}
} catch(IOException e) {
e.printStackTrace();
}
}
private static void print(String s) {
System.out.println(s);
}
}
EchoClient.java
package edu.dlut.zxf.nio;
import java.util.Set;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
/**
* Echo客户端
* @author finux
*/
public class EchoClient {
public static void main(String[] args) {
ByteBuffer buffer = ByteBuffer.allocate(EchoServer.BUFFER_SIZE);
Selector selector = null;
SocketChannel sc = null;
try {
selector = Selector.open();
sc = SocketChannel.open();
sc.configureBlocking(false);
sc.connect(new InetSocketAddress(InetAddress.getByName(EchoServer.HOST), EchoServer.PORT));
print("客户端启动,准备连接...");
if (sc.isConnectionPending()) {
sc.finishConnect();
}
print("完成连接");
sc.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
boolean writed = false;
boolean down = false;
while (!down && selector.select() > 0) {
Set<SelectionKey> selectionKeys = selector.selectedKeys();
for (SelectionKey key: selectionKeys) {
//int ops = key.readyOps();
//if ((ops & SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE && !writed) {
if (key.isWritable() && !writed) {
System.out.print("Input(bye to end): ");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s = br.readLine();
if (s != null && !s.trim().equals("")) {
buffer.clear();
buffer.put(s.getBytes());
buffer.flip();
sc.write(buffer);
writed = true;
if (s.equals("bye")) {
down = true;
break;
}
}
}
//if ((ops & SelectionKey.OP_READ) == SelectionKey.OP_READ && writed) {
if (key.isReadable() && writed) {
buffer.clear();
sc.read(buffer);
buffer.flip();
byte[] b = new byte[buffer.limit()];
buffer.get(b);
print(new String(b));
writed = false;
}
}
selectionKeys.clear();
}
} catch(IOException e) {
e.printStackTrace();
}
}
private static void print(String s) {
System.out.println(s);
}
}
当然EchoClient也可以像下面这样来实现:
EchoClient2.java
package edu.dlut.zxf.nio;
import java.util.Set;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
/**
* Echo客户端2
* @author finux
*/
public class EchoClient2 {
public static void main(String[] args) {
ByteBuffer buffer = ByteBuffer.allocate(EchoServer.BUFFER_SIZE);
Selector selector = null;
SocketChannel sc = null;
try {
selector = Selector.open();
sc = SocketChannel.open();
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_CONNECT);
sc.connect(new InetSocketAddress(InetAddress.getByName(EchoServer.HOST), EchoServer.PORT));
print("客户端启动,准备连接...");
boolean writed = false;
boolean down = false;
while (!down && selector.select() > 0) {
Set<SelectionKey> selectionKeys = selector.selectedKeys();
for (SelectionKey key: selectionKeys) {
//int ops = key.readyOps();
//if ((ops & SelectionKey.OP_CONNECT) == SelectionKey.OP_CONNECT) {
if (key.isConnectable()) {
print("完成连接!");
if (sc.isConnectionPending()) {
sc.finishConnect();
}
sc.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
}
//if ((ops & SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE && !writed) {
if (key.isWritable() && !writed) {
//从准备IO中读取内容
System.out.print("Input(bye to end): ");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s = br.readLine();
if (s != null && !s.trim().equals("")) {
buffer.clear();
buffer.put(s.getBytes());
buffer.flip();
sc.write(buffer);
writed = true;
if (s.equals("bye")) {
down = true;
break;
}
}
}
//if ((ops & SelectionKey.OP_READ) == SelectionKey.OP_READ && writed) {
if (key.isReadable() && writed) {
buffer.clear();
sc.read(buffer);
buffer.flip();
byte[] b = new byte[buffer.limit()];
buffer.get(b);
print(new String(b));
writed = false;
}
}
selectionKeys.clear();
}
} catch(IOException e) {
e.printStackTrace();
}
}
private static void print(String s) {
System.out.println(s);
}
}
但是这样的话,显然EchoClient2中的while循环中的for循环(若有n次),在每次循环中都会多出n-1次if判断,就是下面这个:
if (key.isConnectable()) {
所以,我个人更喜欢第一个EchoClient,呵呵,不用注册SelectionKey.OP_CONNECT监听事件。呵呵...
分享到:
相关推荐
java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现Reactor模型源码java基于NIO实现...
java nio 实现socketjava nio 实现socketjava nio 实现socketjava nio 实现socketjava nio 实现socket
基于Java NIO实现五子棋游戏.zip基于Java NIO实现五子棋游戏.zip 基于Java NIO实现五子棋游戏.zip基于Java NIO实现五子棋游戏.zip 基于Java NIO实现五子棋游戏.zip基于Java NIO实现五子棋游戏.zip 基于Java NIO实现...
用java编写的nio通信的例子,nio是io编程的新版本,比io较流行。同时本例子是适用socket通信的。可以在此基础上,添加您的个人应用。本例子适用于:java通信的学习者,android平台通信的学习者。
用nio实现异步连接池
基于事件的 NIO 多线程服务器
NULL 博文链接:https://wjy320.iteye.com/blog/2002237
基于Spring Boot + NIO实现的电商平台见证宝服务
NIO实现客户端与客户端之间的通信,通过中心服务进行消息转发。
mongodb的开发和nio实现
通过NIO技术实现邮件接收
Java编写的简易聊天工具,使用NIO实现非阻塞socket通信,使用Java原生sdk实现,可以运行。
基于nio 简易聊天室的服务端 客户端,有界面
NIO编程实现实例,
use telnet as client , and implements server using nio
JDK1.4提供的无阻塞I/O(NIO)有效解决了多线程服务器存在的线程开销问题,但在使用上略显得复杂一些。许多基于NIO的多线程服务器程序往往直接基于选择器(Selector)的Reactor模式实现。这种简单的事件机制对于较...
java jre7里的nio实现稳健监控,比jre6新添的watchService服务
适合于文件小但数量比较大的文件传输 传输速度比传统的流IO要快很多,刚接触nio不久,希望有朋友能对它再进行优化,相信很多项目里用的上
这是一个用java NIO 实现的简单多线程服务器有客户端例子,仅供学习参考。