您的位置:首页 > 编程语言 > Java开发

【练习代码】写了基于java nio的RepeatServer -- by auzll

2013-10-09 09:18 417 查看
        昨天在翻看mina源码时,突然想起我貌似还没直接写过基于java nio的代码,于是今天想抓紧练习下,写段小程序。

 

        这段小程序可以在terminal用telnet连服务器端,输入内容,当服务器收到内容之后,会在控制台打印输出,接着再把这些内容稍做“包装”并返回给客户端terminal。程序里面还支持是否强制使用java epoll (配置个系统参数 java.nio.channels.spi.SelectorProvider = sun.nio.ch.EPollSelectorProvider就可以了),不过当然这得看运行环境了,对linux版本和java版本都有要求。下面直接贴贴代码:

 

package niotest;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;

/**
* 基于java nio的RepeatServer。
* 可以在terminal用telnet连服务器端,输入内容,当服务器收到内容之后,会在控制台打
* 印输出,接着再把这些内容稍做“包装”并返回给客户端terminal。
*
* @author auzll
*/
public final class RepeatServer {
private ServerSocketChannel serverSocketChannel;
private Selector selector;

private static final String SELECTOR_PROVIDER_KEY = "java.nio.channels.spi.SelectorProvider";
private static final String EPOLL_SELECTOR_CLASS = "sun.nio.ch.EPollSelectorProvider";

public RepeatServer(boolean epoll, int port) throws IOException {
if (epoll) {
// 强制设置使用java epoll,需要linux和java版本的支持
// 在我写这个测试代码的时候,我的机器环境是默认使用了EPollSelectorProvider
System.setProperty(SELECTOR_PROVIDER_KEY, EPOLL_SELECTOR_CLASS);
}

serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.socket().setReuseAddress(true);
serverSocketChannel.bind(new InetSocketAddress(port));

selector = Selector.open();

// 仅注册OP_ACCEPT
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

System.out.println(String.format("*** Server start on %d , selector provider class is %s ***",
port, selector.provider().getClass().getName()));
}

/**
* 处理客户端连接,并注册读事件
*/
private void handleAcceptable(SelectionKey readyKey) throws IOException {
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) readyKey.channel();

SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);

ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
socketChannel.register(selector,
SelectionKey.OP_READ,
byteBuffer);
}

/**
* 处理读事件
*/
private void handleReadable(SelectionKey readyKey) throws IOException {
SocketChannel socketChannel = (SocketChannel) readyKey.channel();

ByteBuffer readBuff = ByteBuffer.allocate(1024);
Charset charset = Charset.defaultCharset();
boolean gotData = false;

while ( socketChannel.read(readBuff) > 0 ) {
gotData = true;

// 注册写事件
readyKey.interestOps(readyKey.interestOps() | SelectionKey.OP_WRITE);

readBuff.flip();
CharBuffer charBuffer = charset.decode(readBuff);

String repeatData = "We got: [" + charBuffer.toString().trim() + "]\r\n";
System.out.println(repeatData);

ByteBuffer attachBuff = (ByteBuffer) readyKey.attachment();
attachBuff.clear();
attachBuff.put(charset.encode(repeatData));
}

if (!gotData) {
// 完全读不到数据的情况下,取消注册读事件
readyKey.interestOps(readyKey.interestOps() & ~SelectionKey.OP_READ);
}
}

/**
* 处理写事件
*/
private void handleWriteable(SelectionKey readyKey) throws IOException {
SocketChannel socketChannel = (SocketChannel) readyKey.channel();

ByteBuffer attachBuff = (ByteBuffer) readyKey.attachment();
attachBuff.flip();
socketChannel.write(attachBuff);

// 取消注册写事件
readyKey.interestOps(readyKey.interestOps() & ~SelectionKey.OP_WRITE);
}

/**
* 开始服务
*/
public void start() throws IOException {
int selected = 0;
while ((selected = selector.select()) > 0) {
System.out.println("selected is " + selected);

Iterator<SelectionKey> readyKeys = selector.selectedKeys().iterator();
while (readyKeys.hasNext()) {

SelectionKey readyKey = readyKeys.next();
readyKeys.remove();

if (!readyKey.isValid()) {
continue;
}

if (readyKey.isAcceptable()) {
handleAcceptable(readyKey);
}

if (readyKey.isReadable()) {
handleReadable(readyKey);
}

if (readyKey.isWritable()) {
handleWriteable(readyKey);
}
}
}
}

public static void main(String[] args) throws Exception {
// 开始测试
new RepeatServer(false, 9876).start();
}
}

  

        发布在 http://auzll.iteye.com
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: