gloox接收消息

来源:互联网 发布:cydia软件源2016 编辑:程序博客网 时间:2024/05/01 17:06

通过前面的描述,当和服务器建立了连接之后,就可以和服务器进行通讯了,今天先说一下接收远端发送来的文本消息的方式吧。

在接收消息之前,需要明确一件事情,就是一旦你登陆至服务器之后,随时有可能有人人给你发来消息,所以应该考虑的是你需要做一个死循环,不断的监听消息,如果有消息之后,根据消息的不同形式,处理它。当然不用担心,觉得用个死循环很影响效率,实际上做过socket的就明白了,当你调用接收消息的函数时,是会阻塞的,如果没有消息,就阻塞,这样就不会浪费资源了。另外由于阻塞的缘故,所以我们不应该在你的主进程中来做接收消息这样的事情,而是通过一个线程,来专门做消息的接收。当你连接至服务器成功之后,就可以启动一个新的线程,在这个线程中利用前面创建好的客户端实例进行消息的接收了。当然,你可以不用阻塞的方式进行接收消息,而是用非阻塞的方式,但是,我觉得做为客户端而言,用阻塞方式更好一些,对于使用非阻塞,在做服务器端时很有用,但是对于客户端而言就显得没有必要了,在我的使用中,客户端都是使用的是阻塞的方式进行接收远端文本数据的。

前面已经说明,当你连接至服务器之后,你会获得一个客户端实例对象(Client),如果一直要保持连接的话,该实例对象应该一直存在。Client这个对象提供了一个recv()的该方法,通过该方法,就可以接收来自远端的消息了(recv文法默认是阻塞的方式的,如果不需要阻塞,可以通过其参数设置就可以了)。

Gloox在接收远端发来的消息时,会调用一个接口的实现类,该接口为:MessageSessionHandler,这个接口里面提供了一个handleMessageSession( MessageSession *session ) = 0方法,当远端有文本消息发来时,Socket接收数据中会创建一个MessageSession实例对象,表明有一个会话产生(一个无端与本地的会话就有一个对应的MessageSession对象),这时如果你注册了实现MessageSessionHandler接口的实现类,则客户端Client会自动调用你的实现类中的handleMessageSession(处理消息会话)接口。HandMessageSession的函数表现形式为:

virtual void handleMessageSession( MessageSession *session )

传入的参数MessageSession里面含有会话的相关信息,此时,如果你希望能获得里面的相关信息,则应该注册一个接口实现类,则程序将会自动调用你的接口实现类,这个接口类名为:MessageHandler,从字面意思可以看出,注册的这个接口类应该是关于收到的消息的处理接口,也就是说如果你实现了这个接口,并注册至MessageSession对象中,则你将会得到你所需要的消息,注册MessageHandler接口实现类的方法是调用MessageSession参数传入的session->registerMessageHandler( this );方式,示例代码中的this指的是接收消息类,该类实现了MessageHandler中的handleMessage方法。MessageHandler中的virtual void handleMessage( Stanza *stanza, MessageSession *session = 0 )方法就是你需要实现的,同时可以在该方法内得到你所需要的文本信息。下面是得到这样的文本信息的示例代码:

std::string msg =  stanza->body();//也即通过stanza参数传入的变量,通过得到其中的//body就可以得到无端给你发来的文本消息了。

stanza->from()可以获得发送给你的远端的一个完整的JID号,这个很有用,因为你得区分是谁给你发来的消息。当然你可以获得一些其他的可能对你有用的信息,我这里暂且只举这两个通常都要用到的。

如果你得到了所想要的信息,并且也知道了是谁发给你的,这时你就可以在你的表现层里面进行进一步的处理了,当然应该是在你实现的MessageHandler中的handleMessage方法里面,比如你用MFC来做显示的话,这里就可以先通过获得MFC中相关的显示文本内容的地方的句柄,然后再将获得的文本信息写入即可。

说到接收的文本信息,通常还有一个问题,就是关于文本字体,颜色等相关的属性问题,这在XMPP标准协议中并没有这方面的文档,主要原因我觉得是因为在文本样式显示上的表现标准不相同,比如在WEB的文本显示和C/S模式下的文本显示等。不过关于XMPP协议有一个扩展的协议提到了这个问题,这个扩展协议扩展了一个叫做XHTML的扩展,从名字上看,应该是和WEB方面的文本样式表现差不多。由于这个不是标准使用的,而是建议使用的,在我的了解中,很多都是根据自己的需求,做了自己的扩展,而并没有参考XHTML进行扩展。

那么如何进行文本样式的扩展呢,其实从接收文本消息的那个接口实现类的方法中可以看出,当我们通过stanza->body()时,就可以获得一个std::string的文本内容,试想一下,如果这个字符串型的文本内容是这样的表现,它应该是什么意思呢?

<style size=’12px’ color=’red’>您好,世界</style>

从上面的示例来看,它应试表达的是传输的文本内容是“您好,世界”,而这句文本内容大小应该是12象素,显示的颜色应该是红色显示。可是我们通过stanza->body()之后,得到的是除了文本内容之外,还含有其对应的样式表现。那么应该怎么来分离内容与表现呢?

你可以通过字符串关键字来截取上面收到的文本信息,这样可以获得文本内容和样式,不过这个方法并不是很好的方式,虽然可以做得到。gloox内部提供了一个方法来处理这样的表现,这也是为了考虑自行扩展的原因出现的。使用Parser类就可以实现将字符串内容转换为面向对象的方式来操作,你就可以通过获得属性和值的方式来获得你想要的表现与内容了。Parser类的构造函数要求是一个继承了接口实现类的函数,该接口类是:TagHandler,从字面意思可以看出,是要求用户实现这个处理Tag值的接口,这个接口里面含有一个抽象方法,是void handleTag( Tag *tag ) ;这样就可以解析你所收到的那样的字符串了,Tag标识的使用,可以参考gloox示例中的test里面的相关使用方法,这里只做一个使用的示例:

Parser pp(this);    //我这里的this是指的接收消息的类,其中实现了TagHandler接口中的//handleTag方法。

       pp.feed(stanza->body());//当调用这个语句时,就会调用handleTag方法了。

下面是我的handleTag的处理方法实现

void MyRecvMessage::handleTag( Tag *tag )

{

       std::cout<<tag->xml()<<std::endl;

       string fontSize = tag->findAttribute("size");//得到文本大小

       std::cout<<fontSize<<std::endl;    

      

       string msgtt = tag->cdata();//得到文本内容

}

另外还有一个地方需要注意,就是关于handleMessageSession( MessageSession *session )方法的实现类中,session对象是在gloox内部创建的,需要你将其删除掉,如果你不需要了,删除方法是调用Client对象中的disposeMessageSession方法,即可删除掉session对象了,示例代码:client->disposeMessageSession( m_session );如果不删除这个,则有内存泄露的危险。

那么这个session是个什么东东呢?它的意思是当你和远端,或者远端和你有消息发送或者接收时,就会创建一个Session对象,用这个对象来存储交互的信息,所以当你处理这个对象里面的信息之后,就可以将其删除掉了。具体的使用情况可以参考gloox中的示例程序中的相应地方。至于示例程序中的处理消息事件和聊天状态的句柄的使用,则可以通常查看相关的源文件的注释,可以看出来大概是如何使用和在什么情况下使用了。

如果远端继续给你发消息的话,因为你已经删除了对应的Session对象,所以gloox后台又会创建一个MessageSession对象的,所以对于MessageSession对象的管理是一个值得好好考虑的问题了,同样对于向远端发送文本消息也一样存在着这个MessageSession对象的管理问题。因为一个很明显的现象,就是你和远端的某一个JID进行通话,至于是你结束你们之间的通话,还是远端结束你们之间的通话这个是并不明确的,也是不定时的,比如远端在某一个时刻给你发了消息,他有可能就只发送了这一个消息,就不再发送了,这时你可以将MessageSession删除掉(调用Client对象中的disposeMessageSession方法),但是你完全也有可能还会和你继续通信,所以你可以不用删除这个MessageSession对象。这样只要这个MessageSession对象一直保留着,你就可以随时和远端进行通讯了。但是如果有很多远端都要和你通讯,而你不删除这个MessageSession对象的话,则内存中将会有很多的这样的对象,而实际中,可能有些对象应该已经过期了,所以应该删除之。

删还是不删,是个问题,因为删的话,可能这个会话还在继续,而频繁的创建删除对象,是会带来一定的开销的,如果不删的话,则可能这个会话已经不存在了。所以这里有个策略的东西存在。你得根据你的需求和所考虑的情况来做决策,以更好的管理这些MessageSession对象。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 收银机关机时才上传数据是怎么办 刚做的系统玩cf卡屏怎么办 办健康证的资料掉了怎么办 刚刚办得的健康证掉了怎么办 房子都过户了银行贷不了款怎么办 我要办大病迁出应该怎么办啊? 遗产继承后户口没地迁出怎么办 安徽蒙城怎么办去韩国的签证的 夜间有人私自收停车费应该怎么办 上次摸不到环尾丝这次摸到了怎么办 法院判决书下来后对方不给钱怎么办 法院判决书下来了钱还保全么怎么办 深圳路边泊车不知道泊车编号怎么办 当事人进拘留所了我的工资怎么办 昆明公租房住满5年后怎么办 昆明公租房房子到期缴纳金怎么办 看守所犯人银行卡里钱没用完怎么办 中国邮政迟迟没有把信件寄到怎么办 拘留15天放出来还不肯还钱怎么办 人死在拘留所不让看监控怎么办 家人吸毒可他又不愿强戒怎么办 容留他人吸毒时签了强戒怎么办 拘留后发现被拘留是人大代表怎么办 执行局要拘留人找不到人怎么办 开设赌场罪拘留37天了该怎么办 对治安处罚光罚款不拘留怎么办 打架和解后警察不给消案怎么办 12个人片诈骗刑拘了28天怎么办 交警拘留几天后还是没钱赔偿怎么办 平安车主信用卡车牌号填错了怎么办 起诉借钱的人逮起来了怎么办 在法院查不到坐牢人的档案怎么办 人被冤枉敲诈勒索进看守所了怎么办 打架被拘留孩子怎么办三周了 技师被拘留她的家人该怎么办 我是担保人贷款人跑了我该怎么办 公司依旷工理由辞退我该怎么办 试工两天被辞退了不发工资怎么办 员工在单位被打监控调不出来怎么办 老师罚做60张试卷家长该怎么办 孩子在幼儿园被老师打该怎么办