最近温习下nio API,无聊写个Echo服务,直接上代码了,有点懒,具体细节不解释,查阅API或源码吧,没有公开的src就反编译下。
EchoServer.java
package com.iteye.finux.echo;
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.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* 有关Selector的一些操作尽可能放同一个线程处理
* @author zhu
*
*/
public class EchoServer implements Runnable {
private int port;
private InetAddress host;
private ServerSocketChannel channel;
private Selector selector;
private ByteBuffer buffer = ByteBuffer.allocate(1024);
/**
* 若要保证所有信息都传回client, 这里可以把byte[]改为队列或其他容器
*/
private Map<SocketChannel, byte[]> messages = new HashMap<SocketChannel, byte[]>();
public EchoServer(InetAddress host, int port) throws Exception {
this.host = host;
this.port = port;
channel = ServerSocketChannel.open();
channel.configureBlocking(false);
selector = Selector.open();
}
/**
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
try {
channel.socket().bind(new InetSocketAddress(host, port));
channel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
int count = selector.select();
if (count < 1) {
continue;
}
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
if (!key.isValid()) {
continue;
}
if (key.isAcceptable()) {
SocketChannel ch = ((ServerSocketChannel)key.channel()).accept();
ch.configureBlocking(false);
ch.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
read(key);
} else if (key.isWritable()) {
write(key);
}
}
}
} catch(Exception ex) {
ex.printStackTrace();
}
}
/**
* 读操作
* @param key
* @throws IOException
*/
private void read(SelectionKey key) throws IOException {
SocketChannel aChannel = (SocketChannel)key.channel();
buffer.clear();
int num = aChannel.read(buffer);
if (num == -1) {
key.cancel();
} else if (num > 0) {
buffer.flip();
byte[] buf = Arrays.copyOfRange(buffer.array(), 0, num);
messages.put(aChannel, buf);
//将对应Channel注册写事件
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
System.out.println("read from: " + aChannel.socket().getRemoteSocketAddress() +
"; message: " + new String(buf));
}
}
/**
* 写操作
* @param key
* @throws IOException
*/
private void write(SelectionKey key) throws IOException {
SocketChannel aChannel = (SocketChannel)key.channel();
byte[] buf = messages.get(aChannel);
if (buf != null) {
messages.remove(aChannel);
key.interestOps(SelectionKey.OP_READ);
buffer.clear();
buffer.put(buf);
buffer.flip();
aChannel.write(buffer);
System.out.println("write to: " + aChannel.socket().getRemoteSocketAddress() +
"; message: " + new String(buf));
}
}
public static void main(String[] args) throws Exception {
EchoServer server = new EchoServer(InetAddress.getLocalHost(), 8080);
EchoClient.threadStart(server);
}
}
EchoClient.java
package com.iteye.finux.echo;
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.SocketChannel;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
/**
* @author zhu
*
*/
public class EchoClient implements Runnable {
private int port;
private InetAddress host;
private SocketChannel channel;
private Selector selector;
private ByteBuffer buffer = ByteBuffer.allocate(1024);
private LinkedList<byte[]> messages = new LinkedList<byte[]>();
public EchoClient(InetAddress host, int port) throws Exception {
this.host = host;
this.port = port;
channel = SocketChannel.open();
channel.configureBlocking(false);
selector = Selector.open();
}
@Override
public void run() {
try {
channel.connect(new InetSocketAddress(host, port));
channel.register(selector, SelectionKey.OP_CONNECT);
while (true) {
synchronized (messages) {
//检查队列是否有可写的数据
if (!messages.isEmpty()) {
SelectionKey key = channel.keyFor(selector);
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
}
}
int count = selector.select();
if (count > 0) {
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
if (!key.isValid()) {
continue;
}
if (key.isConnectable()) {
channel.finishConnect();
channel.register(selector, SelectionKey.OP_READ);
} else if (key.isWritable()) {
write(key);
} else if (key.isReadable()) {
read(key);
}
}
}
}
} catch(Exception ex) {
ex.printStackTrace();
}
}
/**
* 向服务端发送数据
* @param msg
*/
public void send(byte[] msg) {
synchronized(messages) {
messages.addLast(msg);
//将阻塞中的select调用直接返回
selector.wakeup();
}
}
/**
* 写操作
* @param key
* @throws IOException
*/
private void write(SelectionKey key) throws IOException {
SocketChannel aChannel = (SocketChannel)key.channel();
synchronized(messages) {
if (!messages.isEmpty()) {
byte[] buf = messages.getFirst();
messages.removeFirst();
buffer.clear();
buffer.put(buf);
buffer.flip();
aChannel.write(buffer);
key.interestOps(SelectionKey.OP_READ);
System.out.println("write to: " + aChannel.socket().getRemoteSocketAddress() +
"; message: " + new String(buf));
}
}
}
/**
* 读操作
* @param key
* @throws IOException
*/
private void read(SelectionKey key) throws IOException {
SocketChannel aChannel = (SocketChannel)key.channel();
buffer.clear();
int len = aChannel.read(buffer);
if (len > 0) {
byte[] buf = Arrays.copyOfRange(buffer.array(), 0, len);
System.out.println("read from: " + aChannel.socket().getRemoteSocketAddress() +
"; message: " + new String(buf));
}
}
static void threadStart(Runnable runnable) {
Thread thread = new Thread(runnable);
thread.setName(runnable.getClass().getSimpleName());
thread.start();
}
public static void main(String[] args) throws Exception {
EchoClient client = new EchoClient(InetAddress.getLocalHost(), 8080);
threadStart(client);
CommandReader reader = new CommandReader(client);
threadStart(reader);
}
}
/**
* 标准输入读取数据
* @author zhu
*
*/
class CommandReader implements Runnable {
private EchoClient client;
private byte[] buffer = new byte[1024];
public CommandReader(EchoClient client) {
this.client = client;
}
/**
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
try {
while (true) {
int len = System.in.read(buffer);
if (len == -1) {
break;
} else if (len > 0) {
byte[] buf = Arrays.copyOfRange(buffer, 0, len);
client.send(buf);
}
}
} catch(IOException ex) {
ex.printStackTrace();
}
}
}
分享到:
相关推荐
基于nio 简易聊天室的服务端 客户端,有界面
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实现非阻塞socket通信,使用Java原生sdk实现,可以运行。
NULL 博文链接:https://wjy320.iteye.com/blog/2002237
用java编写的nio通信的例子,nio是io编程的新版本,比io较流行。同时本例子是适用socket通信的。可以在此基础上,添加您的个人应用。本例子适用于:java通信的学习者,android平台通信的学习者。
基于Spring Boot + NIO实现的电商平台见证宝服务
NIO实现客户端与客户端之间的通信,通过中心服务进行消息转发。
mongodb的开发和nio实现
通过NIO技术实现邮件接收
基于事件的 NIO 多线程服务器
用nio实现异步连接池
使用Java NIO编写高性能的服务器
JAVA NIO 简单PFT 文件服务 上传 下载 列表
tuna 是一个基于NIO的简单http服务器,简单的实现了反向代理和负载均衡 这是tuna的配置文件 #this is config file for tuna #some common config keepalived: 5000 username: root password: root proxyServer: ...
NIO编程实现实例,
use telnet as client , and implements server using nio
使用NIO方式完成简单的通信,简单消息协议“消息头(长度+命令字) + 消息体”。