为了更加准确理解Mina框架的工作原理,在这里推出两篇代码,是说明Java Nio TCP 服务端与客户端的实现,实际上Mina就是对这两篇代码的一个封装与优化和功能的完善
1,Java Nio ServerSocket 篇
package cn.std.test;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
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.nio.charset.Charset;
public class TCPIPNIOService {
public static void main(String[] args) {
int port = 9528;
try {
//打开Selector,从而获取Selector 实例对象。
Selector selector = Selector.open();
//打开ServerSocketChannel,从而获取ServerSocketChannel 实例对象。
ServerSocketChannel channel = ServerSocketChannel.open();
//获取ServerSocket 对象,从而进行监听端口等的设置
ServerSocket serverSocket = channel.socket();
//指定服务器端监听的端口。
serverSocket.bind(new InetSocketAddress(port));
System.out.println("Server listen on port: "+port);
//将Channel 设置为非阻塞模式。
channel.configureBlocking(false);
//向ServerSocketChannel 实例对象注册selector 实例对象和所感兴趣的事件,
// 例如,SelectionKey.OP_ACCEPT、SelectionKey.OP_READ 等。
channel.register(selector, SelectionKey.OP_ACCEPT);
//循环以保证正常情况下服务器端一直处于运行状态。
while(true){
//获取selector 实例对象中需要处理的SelectionKey 的数量。
int nKeys = selector.select(1000);//1000ms
if(nKeys>0){
//当selector 实例对象中需要处理的SelectionKey 的数量大于零时,
//遍历selector.selectedKeys,以对每个SelectionKey 的事件进行处理。
for(SelectionKey key:selector.selectedKeys()){
//判断SelectionKey 的类型是否为客户端建立连接的类型
if(key.isAcceptable()){
//当SelectionKey 的类型为acceptable 时,
//从SelectionKey 中获取其绑定的ServerSocketChannel对象。
ServerSocketChannel server = (ServerSocketChannel)key.channel();
//接受客户端建立连接的请求,并返回SocketChannel 对象。
SocketChannel sc = server.accept();
if(sc==null){
continue;
}
//将SocketChannel设置为非阻塞模式
sc.configureBlocking(false);
//向SocketChannel 注册感兴趣的事件类型,
//支持的有: SelectionKey.OP_READ 和SelectionKey.OP_WRITE。
sc.register(selector, SelectionKey.OP_READ);
//判断所获取的SelectionKey 是否为readable,如为则意味着有消息流在等待处理。
}else if(key.isReadable()){
ByteBuffer buffer = ByteBuffer.allocate(1024);
//当SelectionKey 的类型为readable 时,
//从SelectionKey 中获取其绑定的SocketChannel对象
SocketChannel sc = (SocketChannel)key.channel();
int readBytes = 0;
String message = null;
try {
int ret = 0;
try {
//采用SelectionKey 中绑定的SocketChannel 对象读取消息流
while((ret=sc.read(buffer))>0){
readBytes+=ret;
}
} catch (Exception e) {
// TODO: handle exception
readBytes = 0;
e.printStackTrace();
}
finally{
buffer.flip();
}
if(readBytes>0){
message = Charset.forName("UTF-8").decode(buffer).toString();
buffer = null;
}
} catch (Exception e) {
// TODO: handle exception
}
finally{
if(buffer!=null){
buffer.clear();
}
}
if(readBytes>0){
System.out.println("Message from client: "+message);
if("quit".equalsIgnoreCase(message.trim())){
sc.close();
selector.close();
System.out.println("Server has been shutdown");
System.exit(0);
}
String outMessage = "Server response: "+message;
//采用SelectionKey 中绑定的SocketChannel 对象输出消息流。
sc.write(Charset.forName("UTF-8").encode(outMessage));
}
}
}
selector.selectedKeys().clear();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
2,Java Nio Client
package cn.std.test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
public class TCPIPNIOClient {
public static void main(String[] args) {
int port = 9528;
SocketChannel channel;
try {
//打开SocketChannel
channel = SocketChannel.open();
//将SocketChannel 配置为非阻塞模式。
channel.configureBlocking(false);
SocketAddress target = new InetSocketAddress("127.0.0.1",port);
//连接到指定的目标地址。
channel.connect(target);
//打开Selector
Selector selector = Selector.open();
//向SocketChannel 中注册Selector 对象以及所感兴趣的连接事件
//(例如连接建立、连接可读以及连接可写等)。
channel.register(selector,SelectionKey.OP_CONNECT);
BufferedReader systemIn = new BufferedReader(new InputStreamReader(System.in));
//遍历。
while(true){
if(channel.isConnected()){
String command = systemIn.readLine();
//向SocketChannel 中写入ByteBuffer 对象数据。
channel.write(Charset.forName("UTF-8").encode(command));
if(command==null||"quit".equalsIgnoreCase(command.trim())){
systemIn.close();
channel.close();
selector.close();
System.out.println("Client quit");
System.exit(0);
}
}
//从Selector 中获取是否有可读的key 的信息。
int nKeys = selector.select(1000);
if(nKeys>0){
//遍历selector 中所有的key。
for(SelectionKey key:selector.selectedKeys()){
//判断SelectionKey 是否为连接建立的事件。
if(key.isConnectable()){
//从SelectionKey 中获取其对应的SocketChannel。
SocketChannel sc = (SocketChannel)key.channel();
sc.configureBlocking(false);
sc.register(selector,SelectionKey.OP_READ);
//完成连接的建立(TCP/IP 的三次握手)。
sc.finishConnect();
//判断SelectionKey 是否为可读的信息。
}else if(key.isReadable()){
ByteBuffer buffer = ByteBuffer.allocate(1024);
//从SelectionKey 中获取其对应的SocketChannel。
SocketChannel sc = (SocketChannel)key.channel();
int readBytes = 0;
try {
int ret = 0;
try {
//从SocketChannel 中读取数据至ByteBuffer 中
while((ret = sc.read(buffer))>0){
readBytes+=ret;
}
} catch (Exception e) {
// TODO: handle exception
}
finally{
buffer.flip();
}
if(readBytes>0){
System.out.println(Charset.forName("UF-8").decode(buffer).toString());
buffer = null;
}
} catch (Exception e) {
// TODO: handle exception
}
finally{
if(buffer!=null){
buffer.clear();
}
}
}
}
selector.selectedKeys().clear();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
说实话,代码读完感觉就懂了,但是如果叫我用一个图形来形象描述出来,还真感觉有点压力,大侠们要是有已经画好的图,感谢贡献,(*^__^*) 嘻嘻……
分享到:
相关推荐
Apache MINA(Multipurpose Infrastructure for Network Applications)是一个Java框架,它提供了高度可扩展的、高性能的网络应用程序开发工具。本文将深入探讨如何使用MINA实现HTTP协议,以及相关的源码分析和实用...
通过阅读Mina2源码分析.doc,你可以了解到实际项目中如何应用Mina框架,包括设置服务器、配置过滤器链、处理网络事件等。这份文档将提供具体案例,帮助你将理论知识转化为实践技能。 总结来说,Apache Mina是一个...
在描述中提到的"包含了所需要的jar包",这意味着这个压缩包可能包含了Mina框架本身、相关的依赖库,例如Apache Commons Logging用于日志记录,可能还有其他辅助库,如Netty或Grizzly等,这些都可能在实现Mina示例时...
《MINA网络通信实例解析》 MINA(Multipurpose Infrastructure for Network Applications)是Apache软件基金会的一个开源项目,它...在实际应用中,结合源码分析和工具辅助,可以更深入地理解和利用MINA的强大功能。
6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...
6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...
6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...
6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...
6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...
6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...
6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...
6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...
6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...
6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...
6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...
6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...
6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...