`

Mina 框架源码解析-辅助篇

 
阅读更多

为了更加准确理解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();
	}
}
}

 说实话,代码读完感觉就懂了,但是如果叫我用一个图形来形象描述出来,还真感觉有点压力,大侠们要是有已经画好的图,感谢贡献,(*^__^*) 嘻嘻……

 

分享到:
评论

相关推荐

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

    Java 源码包 Applet钢琴模拟程序java源码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这款实例会对你有所帮助。 Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来...

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

    笔者当初为了学习JAVA,收集了很多经典源码,源码难易程度分为初级、中级、高级等,详情看源码列表,需要的可以直接下载! 这些源码反映了那时那景笔者对未来的盲目,对代码的热情、执着,对IT的憧憬、向往!此时此...

    java开源包8

    6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...

    java开源包1

    6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...

    java开源包10

    6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...

    java开源包11

    6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...

    java开源包2

    6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...

    java开源包3

    6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...

    java开源包6

    6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...

    java开源包5

    6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...

    java开源包4

    6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...

    java开源包7

    6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...

    java开源包9

    6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...

    java开源包101

    6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...

    Java资源包01

    6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换NFS-RPC自带的协议。 淘宝开放平台JAVA版SDK top4java 设计原则 容易维护扩展(不...

Global site tag (gtag.js) - Google Analytics