`
郭广川
  • 浏览: 68780 次
  • 性别: Icon_minigender_1
  • 来自: 河北
社区版块
存档分类
最新评论

Mina框架传递对象

阅读更多

      接触java的Mina框架已经有很多时间了,在网上也读过了很多的相关文章,发现Mina框架的确是一个值得拿来好好研究的东西,前些日子写了一个山寨QQ项目,其中的通信部分用到了java中自带的InputStream,OutputStream,Writer,Reader等等,感觉其中的很大的一个问题就是难以将事务处理的逻辑层与解析层分离开来,造成整个项目看起来比较臃肿,繁琐,不够模块化,接触Mina后发现mina在这方面做的很是恰到好处。

 

看到文章标题,你或许会有一些疑惑:

     1、Mina框架传递对象是怎么回事

     2、Mina传递对象可以用来做什么

     3、Mina传递对象是怎么进行的

     4、Mina传递对象过程中会遇到什么问题呢

 

      在用原来的java的InputStream,OutputStream,Writer,Reader等进行通信的时候我们会将信息编码转化成字节流等进行信息传递,InputStream,OutputStream是基于字节流的,而Writer,Reader是基于字符的,我们都知道进行通信的服务器和客户端是事先必须定好通信协议,如果我们将<msg>你好吗?</msg>定义为是一条消息,<request>视频</request>定义为一条视频请求,如果客户端将这条消息和请求发送给了服务器,服务器要想得到消息和请求的真正内容(在这里分别是“你好吗?”和“视频”)并进行处理和应答就必须进行信息的解析,就要一条一条的进行判断:1、如果是信息是<msg>……</msg>格式的就将其看做是一条消息;2、如果是<request>……</request>格式的就将其看作是一条请求;3、如果是其他形式就将其视为无效信息,不予处理。当然这不失为一种办法可以进行信息的提取,但是我们会发现在这个过程中信息的发送、接受、解析、处理、应答等都是一条一条的,很是零散,比较难以统一,没有实现消息定义和解析处理过程的分离,这样写好了一个程序,如果日后想要进行改正其中的一条信息格式,就要在整个项目中Ctrl+F了,比较繁琐,还容易出错。

 

      这是我们会自然的想到要用一种东西将各个格式的信息进行分类统一起来并方便进行一些必要的信息处理,为符合这些特点,我们会想到类这个东东恰恰满足了这些性质,我们可以将信息的格式中的内容定义为类的属性,而对这些属性的处理就可以用类中的方法来予以解决,这样就对信息进行了很好的包装。

 

      这种思想有了,那就是在通信的时候直接进行形式上的对象传递(实际上在通信的时候都是最终以字节流的方式进行传递的),那么我们就要找一种工具进行这种形式的信息传递,对了,这种工具就是Mina框架,我们只看他其中的一个方法

public void messageReceived(IoSession session, Object message),这是进行消息接收是能够被 触发的一个方法,参数session代表当前的会话对象,参数message代表接收的到的信息,这时您会发现message的类型是Object型,而类 Object 是类层次结构的根类,当然可以用对象型的作为message啦!前面提到通信的时候都是最终以字节流的方式进行传递的,这样就要进行:对象(客户端)->字节流(客户端)->发送->接收->字节流(服务器)->对象(服务器)的过程,呵呵不用担心,这些繁琐的过程,Mina都提供了很好的底层默认实现所以你只需稍稍敲点代码就行了。

       光说不练还是不行,先上一个程序实例:

      服务器端(1):

package Mina.server;

import java.io.IOException;
import java.net.InetSocketAddress;

import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory;
import org.apache.mina.transport.socket.SocketAcceptor;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;

public class MainServer {
	private static MainServer mainServer = null;
	private SocketAcceptor acceptor = new NioSocketAcceptor();
	private DefaultIoFilterChainBuilder chain = acceptor.getFilterChain();
	private int bindPort = 8888;

	public static MainServer getInstances() {
		if (null == mainServer) {
			mainServer = new MainServer();
		}
		return mainServer;
	}

	private MainServer() {
		chain.addLast("myChin", new ProtocolCodecFilter(
				new ObjectSerializationCodecFactory()));
		acceptor.setHandler(ServerHandler.getInstances());
		try {
			acceptor.bind(new InetSocketAddress(bindPort));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) throws Exception {
		MainServer.getInstances();
	}
}

 

 服务器端(2):

package Mina.server;

import org.apache.mina.core.filterchain.IoFilterAdapter;
import org.apache.mina.core.service.IoHandler;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;

import Mina.Object.UserInfo;

public class ServerHandler extends IoFilterAdapter implements IoHandler {
	private static ServerHandler samplMinaServerHandler = null;

	public static ServerHandler getInstances() {
		if (null == samplMinaServerHandler) {
			samplMinaServerHandler = new ServerHandler();
		}
		return samplMinaServerHandler;
	}

	private ServerHandler() {

	}

	// 当连接后打开时触发此方法,一般此方法与 sessionCreated 会被同时触发
	public void sessionOpened(IoSession session) throws Exception {
	}
	public void sessionClosed(IoSession session) {
	}
	public void messageReceived(IoSession session, Object message)
			throws Exception {	
		if (message instanceof UserInfo) {
			UserInfo text = (UserInfo) message;
			System.out.println("服务器接收到从客户端的姓名:"+text.getName());
			System.out.println("服务器接收到从客户端的QQ:"+text.getQQNum());
		} 
	}

	public void exceptionCaught(IoSession arg0, Throwable arg1)
			throws Exception {

	}

	// 当消息传送到客户端后触发
	public void messageSent(IoSession arg0, Object arg1) throws Exception {
		
	}

	// 当一个新客户端连接后触发此方法.
	public void sessionCreated(IoSession arg0) throws Exception {
		
	}

	// 当连接空闲时触发此方法.
	public void sessionIdle(IoSession arg0, IdleStatus arg1) throws Exception {
		
	}

}

 

 

 

客户端(1):

package Mina.client;

import java.net.InetSocketAddress;

import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory;
import org.apache.mina.transport.socket.nio.NioSocketConnector;

public class MainClient {
	private static MainClient mainClient = null;
	NioSocketConnector connector = new NioSocketConnector();
	DefaultIoFilterChainBuilder chain = connector.getFilterChain();

	public static MainClient getInstances() {
		if (null == mainClient) {
			mainClient = new MainClient();
		}
		return mainClient;
	}

	private MainClient() {
		chain.addLast("myChin", new ProtocolCodecFilter(
				new ObjectSerializationCodecFactory()));
		connector.setHandler(ClientHandler.getInstances());
		connector.setConnectTimeout(30);
		ConnectFuture cf = connector.connect(new InetSocketAddress("localhost",
				8888));
	}

	public static void main(String args[]) {
		MainClient.getInstances();
	}
}

 

客户端(2):

package Mina.client;

import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;

import Mina.Object.UserInfo;

public class ClientHandler extends IoHandlerAdapter {
	private static ClientHandler samplMinaClientHandler = null;
	public static ClientHandler getInstances() {
		if (null == samplMinaClientHandler) {
			samplMinaClientHandler = new ClientHandler();
		}
		return samplMinaClientHandler;
	}

	private ClientHandler() {

	}

	public void sessionOpened(IoSession session) throws Exception {
		session.write("客户端与服务器的会话打开了……");
		UserInfo text=new UserInfo();
		text.setName("梅竹寒香");
		text.setQQNum("972341215");
		session.write(text);
	}

	public void sessionClosed(IoSession session) {
	}

	public void messageReceived(IoSession session, Object message)
			throws Exception {
	}

	public void messageSent(IoSession arg0, Object arg1) throws Exception {
		System.out.println("客户端已经向服务器发送了:"+(String)arg1);
	}
}

 

公共类: 

package Mina.Object;

public class UserInfo implements java.io.Serializable{
	private String name;
	private String QQNum;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getQQNum() {
		return QQNum;
	}
	public void setQQNum(String qQNum) {
		QQNum = qQNum;
	}
	
	
}

 如下建包即可:



 

以上就是对象的收发的简单示例,如果报错,或许会是一下原因:1、包的引进是否妥当 2、是否引入了mina的第三方包(网上有了很多的相关文章,在此就不在赘述了)

 

通过程序您会看到对象已经成功传递并进行了相关属性的输出,对于这个简单的程序我稍做些相关说明:

      1、进行传递的对象所实例化的类要实现java.io.Serializable序列化接口

      2、您会发现实例中的类尤其是相关的IoHandlerAdapter继承类都采用了单实例模式,为什么这样做呢,原因很简单,那就是要在整个通信过程中做到对象session的等实例的单一防止发生“所托非人”的现象

      3、服务器接收到message在进行类判断时用了instanceof关键字

 

如果你看到上面的实例就觉得对象传递的学习已经成功了,那就错了,细心的博友看到这个包结构:



 

 

是不是有点问题呢。

      例如客户端传了一个userinfo对象到服务器,在服务器端判断如果是userinfo对象后就打印出相关信息,我看源码文档其中有这样的建包方式


 
其中服务器和客户端共用了中间的Mina.Object包,这样在收到对象后就能通过instanceof关键字判断是不是useinfo对象,我看了一下,这个方法是可行的,现在的问题是,我们如果编写通讯软件的时候,肯定是服务器和客户端是要分开的,所以那个Mina.Object包是不能共享的,所以问题来了(1)、如果将userinfo放到客户端中,那么该怎么用instanceof进行判断是不是userinfo呢(这时你已经不能再引入服务器中的userinfo了)(2)、如果在客户端和服务器中都编写一个类定义一样的userinfo,可是他们这两个类是分属不同的包,所以是两个不同的类了,这样在用instanceof进行判断的时候也是行不通的;那么我们该用什么方法来进行判断接收到的类是不是userinfo对象呢?
         这个问题把我纠结了很久,在网上面搜了好久也没有解决,最后想了想那个(2)或许可以改动改动就可以解决,问题的关键在于两个UserInfo分属于两个不同的包,如果可以将包名一致就好了,但是在一个工程里面不能同时建立两个命名一样的包,这样你就会发现何不建立两个工程呢一个是服务器,一个是客户端,这样都可以分别建立名字都是Object的包,这样可不可行呢,经过试验果然可以,这样就就解决了上面的问题工程图如下


 
好啦,有了这个工具,您会有什么想法呢?对象传递还可以做什么?那就是可以用它来进行图片,文件的传递啦,这个只是个小小的提示具体怎么实现,就要看各位博友怎么发挥啦!呵呵
  • 大小: 32 KB
  • 大小: 12.5 KB
分享到:
评论
24 楼 zkshun12 2013-07-30  
你好,你写的非常的有用,我想问一个问题,
现在,我用Mina做了客户端,向一个普通Socket服务端发送对象,
在服务端的代码如下:
ObjectInputStream is = null;  
                ObjectOutputStream os = null;  
                try {  
                    is = new ObjectInputStream(new BufferedInputStream(socket.getInputStream()));  //在此处抛出异常:StreamCorruptedException:invalid Stream header 。。。
                    os = new ObjectOutputStream(socket.getOutputStream());  
  
                    Object obj = is.readObject();  
                    User user = (User)obj;  
  
//                    os.writeObject(user);  
//                    os.flush();  
                } catch (IOException ex) {  
                    logger.log(Level.SEVERE, null, ex);  
                } catch(ClassNotFoundException ex) {  
                    logger.log(Level.SEVERE, null, ex);  
                } finally {  
                    try {  
                        is.close();  
                    } catch(Exception ex) {}  
                    try {  
                        os.close();  
                    } catch(Exception ex) {}  
                    try {  
                        socket.close();  
                    } catch(Exception ex) {}  
                }  

那个User对象是实例化了的,请问这个是怎么回事?谢谢
23 楼 sxlnok 2012-05-10  
Socket 怎么给mina发送对象
22 楼 郭广川 2011-03-10  
GuolinLee 写道
序列化很有局限性,传递的消息必须以类作为载体(基本单体),如果传的消息类型,每个都是去写一个类,那还不得累死吗?
用bytebuffer才是王道

我们也可以直接传递一个字符串呀!字符串用来发送短消息,例如“loginOK”,“online”,这些都是可以作为对象传递的呀,短小精悍,而且不用你去序列化,也不用你去转换成buffer去传递,而自己定义的类可以直接进行消息的包装,选择自如,何必只盯着buffer不放
21 楼 GuolinLee 2011-03-10  
序列化很有局限性,传递的消息必须以类作为载体(基本单体),如果传的消息类型,每个都是去写一个类,那还不得累死吗?
用bytebuffer才是王道
20 楼 zhxing 2011-03-10  
一个通讯协议的大小是一个比较敏感的东西,毕竟如果多人聊天,流量必然增大。。到时也就需要去改了。。
19 楼 elvishehai 2011-03-09  
没有接触过了,不知道是用来做什么的.
18 楼 jiefei_download 2011-03-09  
esanone 写道
jiefei_download 写道
有什么办法可以得到一个对象的大小(字节数),而不序列化这个对象?

对于每个数据包,我们必须知道其大小,这往可以在双方的协议里解决(包头),所以方案确实不知道要什么入手。

说了等于没说。
17 楼 郭广川 2011-03-09  
对于博友的回复,我说明一下哈
1、基于上述实现的话客户端就必须是java开发的了,呵呵,或许是局限了些,java和其他语言相比有不足,但有的地方也有很多优势,我的程序实例只是提供一种策略,您可以利用这个策略去开发java比较擅长的客户端软件,至于java不擅长的您进行权衡决定是否采用这一个策略,那就要看开发者的选择喽
2、15楼“你这样子在server项目和client项目都有UserInfo类,万一要改那不是两边都要动”的确这样一来两边都要修改,如果通过原始的那种InputStream,OutputStream,Writer,Reader进行信息解析的话,如果需要功能更新,同样是要进行解析更新的,4楼的“把你公共的文件,比如你上面的UserInfo类,编译打包成一个jar文件,分别引入到客户端和服务端程序中,这样如果你公共文件有变化,可以省去你要修改客户端和服务端”建议不错,可是这还是要修改客户端和服务器的,因为我示例中只有一个userinfo类,如果增加了功能有了个bloginfo类,还是要修改服务器和客户端的(instanceof的类对象判断解析部分的修改是必须的),不知您们有没有其他的更好的当增加新功能时而不用修改解析方式的方法,提出来参考一下
3、通过测试,Mina的性能还是很不错的
4、关于网络的粘包与拆包问题,我还不太清楚,望大家多多指点
16 楼 fory 2011-03-09  
客户端用C++也是可以的。
15 楼 weiqiang.yang 2011-03-09  
这么说的话客户端必须也是java才行
还有客户端和服务端公有的类提取出来成为一个基础项目,其他项目依赖它就可以了
发布的时候打个包一起发布
你这样子在server项目和client项目都有UserInfo类,万一要改那不是两边都要动
14 楼 esanone 2011-03-09  
jiefei_download 写道
有什么办法可以得到一个对象的大小(字节数),而不序列化这个对象?

对于每个数据包,我们必须知道其大小,这往可以在双方的协议里解决(包头),所以方案确实不知道要什么入手。
13 楼 jiefei_download 2011-03-09  
有什么办法可以得到一个对象的大小(字节数),而不序列化这个对象?
12 楼 flashing 2011-03-09  
zhxing 写道
不知道对象序列化的性能怎样。个人愚见是对象序列化能省掉大部分的解码代码,但是这也限制了客户端必须也是java。。序列化后的大小估计也比较大,当作通讯协议好像有点吃力。。

对于mina的性能,好像不错。。

事实上这个玩意性能还可以,不是提吃力。麻烦在于限制死了只能java通信。
11 楼 分离的北极熊 2011-03-09  
传对象太大了吧?而且还需要制定的协议来进行转换,要封装ENCODER 和 DECODER

不然不会知道你传过来的东西是啥的,而且传递的对象在接收方还要存在····
10 楼 jiefei_download 2011-03-09  
esanone 写道
楼主用对象的方式传送,那在decode的时候,如何解决网络的粘包与拆包问题?

从代码来看,根本就没有解决粘包的问题。
9 楼 beifengbei08 2011-03-09  
mina可以自己定义解码类,根据自己的需要来接收,发送……
8 楼 zhxing 2011-03-09  
不知道对象序列化的性能怎样。个人愚见是对象序列化能省掉大部分的解码代码,但是这也限制了客户端必须也是java。。序列化后的大小估计也比较大,当作通讯协议好像有点吃力。。

对于mina的性能,好像不错。。
7 楼 esanone 2011-03-09  
楼主用对象的方式传送,那在decode的时候,如何解决网络的粘包与拆包问题?
6 楼 lovebeaners 2011-03-09  
i2534 写道
不知道LZ有没有搞定文件的传送,这个我一直没有搞定.

mina是字节传送的,把文件读成字节,然后传送,不知道可不可以
5 楼 pywepe 2011-03-09  
lz的山寨QQ很 强大.

怎么你的包名都是大写开头

相关推荐

    Mina通信框架应用示例

    Mina框架主要由以下几部分组成: - NIO框架库:MINA利用Java的非阻塞I/O模型,提供高效的数据传输能力。 - 客户端-服务器框架库:MINA支持多种通信协议,可以构建客户端和服务器端应用。 - 网络socket库:MINA...

    mina框架自定义解编码器

    在MINA框架中,解编码器是数据传输过程中的关键组件,负责将接收到的原始字节流转化为应用程序可以理解的对象,或者将应用程序准备发送的对象编码成字节流。自定义解编码器能帮助我们更好地处理特定的协议格式,...

    mina传输对象的示例

    在标题和描述中提到的“mina传输对象的示例”指的是如何在Mina框架下处理和传输自定义的数据对象。Mina允许开发者通过事件驱动和异步I/O模型来高效地构建网络服务。 Mina的核心组件包括: 1. **Session**: 表示...

    ApacheMINA传递对象实例[借鉴].pdf

    在Apache MINA中传递对象,主要依赖于Java的序列化机制。在这个例子中,`MyRequestObject`和`MyResponseObject`是两个简单的Java对象,它们都实现了`Serializable`接口。这使得这些对象能够被转换为字节流在网络中...

    mina框架--MINA框架是对java的NIO包的一个封装

    MINA框架通过封装NIO,提供了一种更加面向对象和易于使用的API,使得开发者可以更方便地创建高性能、可扩展的网络应用,如TCP和UDP服务器。 在上述代码中,可以看到如何使用MINA框架初始化一个服务器: 1. `...

    mina的高级使用,mina文件图片传送,mina发送文件,mina报文处理,mina发送xml和json

    Apache Mina是一个开源的网络通信应用框架,主要应用于Java平台,它为高性能、高可用性的网络应用程序提供了基础架构。在本文中,我们将深入探讨Mina的高级使用,特别是在文件图片传送、文件发送、XML和JSON报文处理...

    mina框架详解

    - **序列化服务**:除了基本的字节流传输外,Mina还支持Java对象的序列化服务,简化了复杂数据类型在网络间的传递。 - **虚拟机管道通信**:Mina还支持进程间通信,尤其是同一虚拟机内的管道通信,这对于构建分布式...

    mina中文开发手册.pdf

    - **序列化服务**:除了传统的字节流传输,Mina还支持Java对象的序列化服务,简化了复杂数据类型在网络间的传递。 - **虚拟机管道通信**:Mina还支持虚拟机内部的管道通信,这意味着可以在同一个JVM内部高效地进行...

    mina-http-2.0.7.jar.zip_mina_mina 获取POST_mina-http_mina-http-2.0

    MINA框架提供了一种事件驱动的非阻塞I/O模型,这种模型允许服务器处理大量的并发连接,同时保持较低的内存占用。它通过使用NIO(Non-blocking Input/Output)技术,使得服务器在等待数据到来时不会被阻塞,提高了...

    mina简单示例

    标题中的"mina简单示例"指的是使用Apache Mina框架构建一个简单的客户端和服务端的程序。在Java开发中,Mina提供了一种高效的方式来处理网络连接和数据传输,特别适合于构建大型、复杂的网络服务。 描述中的"mina...

    MINA 协议解码过滤器

    过滤器链的概念是MINA框架的核心特性之一,它允许开发者插入自定义的过滤器来处理进来的数据或者发送出去的数据。协议解码过滤器(ProtocolDecoderFilter)就是这样的一个过滤器,它的主要任务是从接收到的原始字节...

    mina文档说明书

    这个“mina文档说明书”包含了MINA框架的详细信息,帮助开发者理解和使用它。 MINA的核心概念包括: 1. **Session**:在MINA中,Session代表了网络连接,它是双向的通信通道。每个连接都会创建一个Session对象,...

    mina 多路分离解码

    mina框架是Apache软件基金会的一个开源项目,它为Java开发者提供了一套高效、功能丰富的网络通信库,主要用于构建高性能的网络应用服务器,如TCP和UDP服务。在mina框架中,“多路分离解码”(Multiplexing Decoding...

    SpringMina

    SpringMina 是一个将Apache Mina框架与Spring框架相结合的项目,主要用于构建高性能、异步的网络应用。SpringMina旨在简化Mina的配置和管理,利用Spring强大的依赖注入(DI)和面向切面编程(AOP)特性,使开发者能...

    Mina小Demo聊天工具

    4. 数据传输:Mina小Demo中的数据传输可能采用了序列化或JSON等格式,以便于在网络间传递对象和消息。 四、脱离Eclipse运行与最小化至托盘 Mina小Demo的可执行特性意味着开发者无需依赖Eclipse或其他IDE,只需将...

    基于Java的源码-高性能Java网络框架 MINA.zip

    - **IoSession**:这是MINA框架中的核心对象,代表了客户端与服务器之间的连接会话。它包含了与连接相关的所有信息,如输入/输出缓冲区、连接状态、事件和属性等。 - **IoHandler**:处理网络事件的接口,如连接...

    MINA TCP简单通信实例

    总结起来,这个“MINA TCP简单通信实例”涵盖了使用MINA框架搭建TCP通信的基本步骤,包括服务端Acceptor的配置、客户端Connector的使用、IoHandler的实现以及数据的发送与接收。同时,通过阅读源码,开发者可以...

    MINA源码与例子

    在"apache-mina-2.0.2"压缩包中,包含了MINA框架的源代码,包括核心库、示例应用、文档和测试代码。通过阅读源码,你可以深入了解MINA的设计思想和实现细节,例如如何实现非阻塞I/O、过滤器链的工作原理、以及如何...

    MinaClient

    总结来说,MinaClient是基于Apache Mina框架在Android平台上实现的网络通信客户端,它利用Mina的高效I/O处理能力,结合MPAndroidChart库进行数据可视化,可以用于创建复杂的网络应用。开发者需要理解Mina的核心组件...

    Mina Socket 源代码

    Mina Socket 是 Apache Mina 项目的一部分,它是一个高性能、可扩展的网络通信框架。Mina 提供了一种简单的方式来构建网络应用,如服务器和客户端,支持多种协议,如 TCP/IP 和 UDP。在这个简单示例中,我们将深入...

Global site tag (gtag.js) - Google Analytics