`
郭广川
  • 浏览: 67289 次
  • 性别: 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框架+常用JAR包

    Mina框架+常用JAR包 Mina框架+常用JAR包 Mina框架+常用JAR包 Mina框架+常用JAR包 Mina框架+常用JAR包 Mina框架+常用JAR包

    mina 框架学习文档

    apache mina 框架的学习文档,通过此文档可以基本了解mina框架。

    java mina框架全套

    java mina框架

    apache mina 框架实例

    apache mina 框架 实例 自定义协议包 自定义编码器 解码器 服务端 客户端

    Apache mina框架入门教程

    该文档较好的介绍了,apache mina框架的使用方法。

    mina框架资源包

    要实现mina框架最基本的资源包,拥有这个就可以实现mina的通讯

    Mina框架入门介绍

    pache Mina Server 是一个网络通信应用框架,也就是说,它主要是对基于TCP/IP、UDP/IP协议栈的通信框架(然,也可以提供JAVA 对象的序列化服务、虚拟机管道通信服务等),Mina 可以帮助我们快速开发高性能、高扩展性...

    mina框架的demo 入门,开发

    mina框架的demo 入门,开发 学习

    Android Mina框架使用

    Android端集成Mina框架实现长连接,完美解决断线重连问题,修复断线重连打开多端口问题。

    Java springboot 整合mina 框架,nio通讯基础教程,mina框架基础教程.zip

    Java_NIO基础教程、MINA教程, 并附上基于springboot 整合mina的基础平台框架,可以直接使用,也可以借鉴下

    mina框架源码及jar包

    apache-mina-2.0.4 mina框架的源码及jar包

    Mina 框架研究与实现

    Mina框架研究与实现 Mina框架研究与实现

    mina框架使用总结

    nio的经典框架mina 在此基础上发展的netty是nio经典之中的经典

    java-mina通信框架详解.docx

    详细介绍mina框架的各个组成部分、服务器端的开发、客户端开发。并根据本人在工程项目中使用的代码,详细讲解了服务器端是客户端实现。实现了json格式的通信、以及文件的上传于下载等功能。图文并茂,以开发者的角度...

    mina传输对象的示例

    mina mina传输对象的示例 mina框架 mina示例

    mina框架demo

    使用MINA框架来开发的网络应用程序代码结构更清晰;MINA框架完成了底层的线程管理;MINA内置的编码器可以满足大多数用户的需求,省去了开发人员消息编码解码的工作。

    Mina通信框架应用示例

    Mina通信框架应用示例,学会运用Mina 框架

    基于Java的mina框架

    基于Java的米娜框架,报告对使用基于Java、websocket协议的网页聊天室的过程和技术做了详细的叙述首先,对现有网页进行了分析与评价。首先, 启动后台服务器,然后连接站点,客户端在pc端输入网站或者在手机端扫...

    apache下的mina框架

    可以使用 TCP/IP、UDP/IP、串口和虚拟机内部的管道等传输方式,是一个开发高性能和高可伸缩性网络应用程序的网络应用框架

    MiNA框架新人指导

    在资金线混有两个技术框架是一定要懂得如何使用的,它们就是MINA和HTTPCLIENT(迓没听过的,就先百度一下) 。支付宝和银行前置机乊间的通讯基本都是使用者两种框架,即使你丌懂SOCKET戒者HTTP很底层的协议也没多大...

Global site tag (gtag.js) - Google Analytics