`
phinecos
  • 浏览: 339964 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Java NIO非阻塞服务器示例

 
阅读更多
以前一直用的是“ervery thread per connection”的服务器端模式,今天试了下NIO非阻塞模式的服务器。 不过java不能实现I/O完成端口模型,这点很遗憾
packagecom.vista.Server;

importjava.io.IOException;
importjava.net.InetSocketAddress;
importjava.net.ServerSocket;
importjava.nio.ByteBuffer;
importjava.nio.channels.SelectionKey;
importjava.nio.channels.Selector;
importjava.nio.channels.ServerSocketChannel;
importjava.nio.channels.SocketChannel;
importjava.util.Iterator;
importjava.util.LinkedList;
importjava.util.Set;

publicclassSelectorServer
{
privatestaticintDEFAULT_SERVERPORT=6018;//默认端口
privatestaticintDEFAULT_BUFFERSIZE=1024;//默认缓冲区大小为1024字节
privateServerSocketChannelchannel;
privateLinkedList<SocketChannel>clients;
privateSelectorreadSelector;
privateByteBufferbuffer;//字节缓冲区
privateintport;

publicSelectorServer(intport)throwsIOException
{
this.port=port;
this.clients=newLinkedList<SocketChannel>();
this.channel=null;
this.readSelector=Selector.open();//打开选择器
this.buffer=ByteBuffer.allocate(DEFAULT_BUFFERSIZE);
}

//服务器程序在服务循环中调用sericeClients()方法为已接受的客户服务
publicvoidserviceClients()throwsIOException
{
Setkeys;
Iteratorit;
SelectionKeykey;
SocketChannelclient;
//在readSelector上调用select()方法,参数1代表如果调用select的时候那么阻塞最多1秒钟等待可用的客户端连接
if(readSelector.select(1)>0)
{
keys
=readSelector.selectedKeys();//取得代表端通道的键集合
it=keys.iterator();
//遍历,为每一个客户服务
while(it.hasNext())
{
key
=(SelectionKey)it.next();
if(key.isReadable())
{//如果通道可读,那么读此通道到buffer中
intbytes;
client
=(SocketChannel)key.channel();//取得键对应的通道
buffer.clear();//清空缓冲区中的内容,设置好position,limit,准备接受数据
bytes=client.read(buffer);//从通道中读数据到缓冲中,返回读取得字节数
if(bytes>=0)
{
buffer.flip();
//准备将缓冲中的数据写回到通道中
client.write(buffer);//数据写回到通道中
}

elseif(bytes<0)
{//如果返回小于零的值代表读到了流的末尾
clients.remove(client);
//通道关闭时,选择键也被取消
client.close();
}

}

}

}

}


publicvoidregisterClient(SocketChannelclient)throwsIOException
{//配置和注册代表客户连接的通道对象
client.configureBlocking(false);//设置此通道使用非阻塞模式
client.register(readSelector,SelectionKey.OP_READ);//将这个通道注册到选择器上
clients.add(client);//保存这个通道对象
}

publicvoidlisten()throwsIOException
{//服务器开始监听端口,提供服务
ServerSocketsocket;
SocketChannelclient;
channel
=ServerSocketChannel.open();//打开通道
socket=channel.socket();//得到与通到相关的socket对象
socket.bind(newInetSocketAddress(port),10);//将scoket榜定在制定的端口上
//配置通到使用非阻塞模式,在非阻塞模式下,可以编写多道程序同时避免使用复杂的多线程
channel.configureBlocking(false);
try
{
while(true)
{//与通常的程序不同,这里使用channel.accpet()接受客户端连接请求,而不是在socket对象上调用accept(),这里在调用accept()方法时如果通道配置为非阻塞模式,那么accept()方法立即返回null,并不阻塞
client=channel.accept();
if(client!=null)
{
registerClient(client);
//注册客户信息
}

serviceClients();
//为以连接的客户服务
}

}

finally
{
socket.close();
//关闭socket,关闭socket会同时关闭与此socket关联的通道
}

}

publicstaticvoidmain(String[]args)throwsIOException
{
System.out.println(
"服务器启动");
SelectorServerserver
=newSelectorServer(SelectorServer.DEFAULT_SERVERPORT);
server.listen();
//服务器开始监听端口,提供服务


}


}

修改版本:

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->packagecom.vista.Server;

importjava.io.BufferedWriter;
importjava.io.FileInputStream;
importjava.io.IOException;
importjava.io.OutputStreamWriter;
importjava.io.PrintWriter;
importjava.net.InetSocketAddress;
importjava.net.ServerSocket;
importjava.nio.ByteBuffer;
importjava.nio.CharBuffer;
importjava.nio.channels.FileChannel;
importjava.nio.channels.SelectionKey;
importjava.nio.channels.Selector;
importjava.nio.channels.ServerSocketChannel;
importjava.nio.channels.SocketChannel;
importjava.nio.charset.Charset;
importjava.nio.charset.CharsetDecoder;
importjava.util.Iterator;
importjava.util.LinkedList;
importjava.util.Set;

publicclassSelectorServer
{
privatestaticintDEFAULT_SERVERPORT=6018;//默认端口
privatestaticintDEFAULT_BUFFERSIZE=1024;//默认缓冲区大小为1024字节
privatestaticStringDEFAULT_CHARSET="GB2312";//默认码集
privatestaticStringDEFAULT_FILENAME="bigfile.dat";
privateServerSocketChannelchannel;
privateLinkedList<SocketChannel>clients;
privateSelectorselector;//选择器
privateByteBufferbuffer;//字节缓冲区
privateintport;
privateCharsetcharset;//字符集
privateCharsetDecoderdecoder;//解码器


publicSelectorServer(intport)throwsIOException
{
this.port=port;
this.clients=newLinkedList<SocketChannel>();
this.channel=null;
this.selector=Selector.open();//打开选择器
this.buffer=ByteBuffer.allocate(DEFAULT_BUFFERSIZE);
this.charset=Charset.forName(DEFAULT_CHARSET);
this.decoder=this.charset.newDecoder();

}


privateclassHandleClient
{
privateStringstrGreeting="welcometoVistaQQ";
publicHandleClient()throwsIOException
{
}

publicStringreadBlock()
{//读块数据
returnthis.strGreeting;
}

publicvoidclose()
{

}

}


protectedvoidhandleKey(SelectionKeykey)throwsIOException
{//处理事件
if(key.isAcceptable())
{//接收请求
ServerSocketChannelserver=(ServerSocketChannel)key.channel();//取出对应的服务器通道
SocketChannelchannel=server.accept();
channel.configureBlocking(
false);
channel.register(selector,SelectionKey.OP_READ);
//客户socket通道注册读操作
}

elseif(key.isReadable())
{//读信息
SocketChannelchannel=(SocketChannel)key.channel();
intcount=channel.read(this.buffer);
if(count>0)
{
this.buffer.flip();
CharBuffercharBuffer
=decoder.decode(this.buffer);
System.
out.println("Client>>"+charBuffer.toString());
SelectionKeywKey
=channel.register(selector,
SelectionKey.OP_WRITE);
//为客户sockt通道注册写操作
wKey.attach(newHandleClient());
}

else
{//客户已经断开
channel.close();
}

this.buffer.clear();//清空缓冲区
}

elseif(key.isWritable())
{//写事件
SocketChannelchannel=(SocketChannel)key.channel();
HandleClienthandle
=(HandleClient)key.attachment();//取出处理者
ByteBufferblock=ByteBuffer.wrap(handle.readBlock().getBytes());
channel.write(block);
//channel.socket().getInputStream().(block);
//PrintWriterout=newPrintWriter(newBufferedWriter(newOutputStreamWriter(
//channel.socket().getOutputStream())),true);
//out.write(block.toString());

}


}

publicvoidlisten()throwsIOException
{//服务器开始监听端口,提供服务
ServerSocketsocket;
channel
=ServerSocketChannel.open();//打开通道
socket=channel.socket();//得到与通到相关的socket对象
socket.bind(newInetSocketAddress(port));//将scoket榜定在制定的端口上
//配置通到使用非阻塞模式,在非阻塞模式下,可以编写多道程序同时避免使用复杂的多线程
channel.configureBlocking(false);
channel.register(selector,SelectionKey.OP_ACCEPT);
try
{
while(true)
{//与通常的程序不同,这里使用channel.accpet()接受客户端连接请求,而不是在socket对象上调用accept(),这里在调用accept()方法时如果通道配置为非阻塞模式,那么accept()方法立即返回null,并不阻塞
this.selector.select();
Iteratoriter
=this.selector.selectedKeys().iterator();
while(iter.hasNext())
{
SelectionKeykey
=(SelectionKey)iter.next();
iter.remove();
this.handleKey(key);

}

}

}

catch(IOExceptionex)
{
ex.printStackTrace();
}

}

publicstaticvoidmain(String[]args)throwsIOException
{
System.
out.println("服务器启动");
SelectorServerserver
=newSelectorServer(SelectorServer.DEFAULT_SERVERPORT);
server.listen();
//服务器开始监听端口,提供服务
}


}

分享到:
评论

相关推荐

    Java NIO非阻塞服务器示例.docx

    Java NIO非阻塞服务器示例.docx

    JavaNIO非阻塞服务器示例.pdf

    JavaNIO非阻塞服务器示例.pdf

    Java-NIO非阻塞服务器示例.docx

    Java-NIO非阻塞服务器示例.docx

    基于java NIO的简单聊天软件示例

    JAVA NIO有两种解释:一种叫非阻塞IO(Non-blocking I/O),另一种也叫新的IO(New I/O),其实是同一个概念。它是一种同步非阻塞的I/O模型,也是I/O多路复用的基础,已经被越来越多地应用到大型应用服务器,成为...

    Java-WebSocket:以100%Java编写的准系统WebSocket客户端和服务器实现

    基础类实现为java.nio ,它允许使用非阻塞事件驱动模型(类似于Web浏览器的 )。 已实现的WebSocket协议版本为: 有关协议版本/草案的更多详细信息。 启用同时引用服务器和客户端示例的扩展。入门依赖管理工具以下...

    nioreactor:无阻塞IOReact器

    由于React堆线程可以在执行IO时饱和,因此nioreactor使用接受器线程将新连接转发到可以在非阻塞模式下处理读取和写入的React堆池。 建筑分布 要求 2.2.0或以上 Java 8或以上 建立: git clone mvn clean install ...

    JAVA上百实例源码以及开源项目

     基于JAVA的UDP服务器模型源代码,内含UDP服务器端模型和UDP客户端模型两个小程序,向JAVA初学者演示UDP C/S结构的原理。 简单聊天软件CS模式 2个目标文件 一个简单的CS模式的聊天软件,用socket实现,比较简单。 ...

    JAVA上百实例源码以及开源项目源代码

     基于JAVA的UDP服务器模型源代码,内含UDP服务器端模型和UDP客户端模型两个小程序,向JAVA初学者演示UDP C/S结构的原理。 简单聊天软件CS模式 2个目标文件 一个简单的CS模式的聊天软件,用socket实现,比较简单。 ...

    Java网络编程(第三版)中文版.part09.rar

    第十二章 非阻塞I/O 391 一个示例客户端 392 一个示例服务器 396 缓冲区 402 通道 421 就绪选择 427 第十三章 UDP数据报和Socket 431 UDP协议 431 DatagramPacket类 433 DatagramSocket类 442 一些有用的...

    Java-WebSocket:用100%Java编写的准系统WebSocket客户端和服务器实现

    基础类实现为java.nio ,它允许使用非阻塞事件驱动模型(类似于Web浏览器的 )。 已实现的WebSocket协议版本为: 有关协议版本/草案的更多详细信息。 启用同时引用服务器和客户端示例的扩展。 入门 依赖管理工具 ...

    java开源包4

    xSocket是一个轻量级的基于nio的服务器框架用于开发高性能、可扩展、多线程的服务器。该框架封装了线程处理、异步读/写等方面。 Java多线程程序死锁检查 JCarder JCarder 是一个用来查找多线程应用程序中一些潜在的...

    java开源包101

    xSocket是一个轻量级的基于nio的服务器框架用于开发高性能、可扩展、多线程的服务器。该框架封装了线程处理、异步读/写等方面。 Java多线程程序死锁检查 JCarder JCarder 是一个用来查找多线程应用程序中一些潜在的...

    java开源包11

    xSocket是一个轻量级的基于nio的服务器框架用于开发高性能、可扩展、多线程的服务器。该框架封装了线程处理、异步读/写等方面。 Java多线程程序死锁检查 JCarder JCarder 是一个用来查找多线程应用程序中一些潜在的...

    java开源包6

    xSocket是一个轻量级的基于nio的服务器框架用于开发高性能、可扩展、多线程的服务器。该框架封装了线程处理、异步读/写等方面。 Java多线程程序死锁检查 JCarder JCarder 是一个用来查找多线程应用程序中一些潜在的...

    java开源包9

    xSocket是一个轻量级的基于nio的服务器框架用于开发高性能、可扩展、多线程的服务器。该框架封装了线程处理、异步读/写等方面。 Java多线程程序死锁检查 JCarder JCarder 是一个用来查找多线程应用程序中一些潜在的...

    java开源包8

    xSocket是一个轻量级的基于nio的服务器框架用于开发高性能、可扩展、多线程的服务器。该框架封装了线程处理、异步读/写等方面。 Java多线程程序死锁检查 JCarder JCarder 是一个用来查找多线程应用程序中一些潜在的...

    java开源包5

    xSocket是一个轻量级的基于nio的服务器框架用于开发高性能、可扩展、多线程的服务器。该框架封装了线程处理、异步读/写等方面。 Java多线程程序死锁检查 JCarder JCarder 是一个用来查找多线程应用程序中一些潜在的...

    java开源包10

    xSocket是一个轻量级的基于nio的服务器框架用于开发高性能、可扩展、多线程的服务器。该框架封装了线程处理、异步读/写等方面。 Java多线程程序死锁检查 JCarder JCarder 是一个用来查找多线程应用程序中一些潜在的...

    java开源包1

    xSocket是一个轻量级的基于nio的服务器框架用于开发高性能、可扩展、多线程的服务器。该框架封装了线程处理、异步读/写等方面。 Java多线程程序死锁检查 JCarder JCarder 是一个用来查找多线程应用程序中一些潜在的...

    java开源包3

    xSocket是一个轻量级的基于nio的服务器框架用于开发高性能、可扩展、多线程的服务器。该框架封装了线程处理、异步读/写等方面。 Java多线程程序死锁检查 JCarder JCarder 是一个用来查找多线程应用程序中一些潜在的...

Global site tag (gtag.js) - Google Analytics