阿不

潜水

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

版权声明:该开源开发包,是基于LumaQQ的基于等价移植到.NET平台下,开发者不直接参与QQ协议的分析工作,移植到.NET平台纯粹是为了方便广大.NET开发者学习和研究之用,并且没有产生任何直接的经济效益,并且纯粹是个人的技术学习研究行为,与本人所在单位没有任何关系。此开发包的用户在使用过程产生的效益和涉及的法律责任与本人没有直接关系。如果影响到您或您的公司利益,敬请谅解并且与我联系,本人会第一时间作出处理。本系列章首发且单发于博客园,由于各种原因不欢迎转载本系列文章,如果您转载了该系列文章请自行承担责任并且转载完整版本,包括版权声明。

QQ,原则上应该说是类似的网络通信类的软件都有一个共同的特点,那就是消息处理的异步性。也就是在这类软件中很注重软件的多线程和异步操作。因为你发送一个数据包后,不可能在服务器还没有返回回复消息前让你的客户端程序一直处于等待状态吧?这时候你只能是发送完数据包后,让你的程序返回正常工作状态等服务器消息的返回。在发送数据时,还有同步发送和步异发送之分,但是这不同我们今天所要介绍的使用方法的范畴,就不多做介绍了。

我今天有收到很多人的询问,问他们调用了接口以后,为什么没有得到正确的数据返回呢?如下的一段代码:

   1: QQUser user = new QQUser(int.Parse(qq), pwd);
   2: client = new QQClient(user);
   3: user.IsUdp = true;
   4: client.LoginServerHost = "219.133.62.8";
   5: client.FriendManager.GetFriendListSuccessed += new EventHandler<QQ.NET.Events.QQEventArgs<QQ.NET.Packets.In.GetFriendListReplyPacket, QQ.NET.Packets.Out.GetFriendListPacket>>(FriendManager_GetFriendListSuccessed);
   6: client.MessageManager.SysRequestAddMeEx += new EventHandler<QQ.NET.Events.QQEventArgs<QQ.NET.Packets.In.SystemNotificationPacket, QQ.NET.Packets.OutPacket>>(MessageManager_SysRequestAddMeEx);
   7: client.Login();
   8: return client.QQUser.Friends.Count;

他问,怎么没有正确返回好友的数量啊?这段至少有以下两个问题:

  1. 如上面介绍,QQ接口调用的事件操作是异步的。也就是你调用了一个接口功能,例如登录或读取好友。那么在你这个接口调用返回后,实际上并没有真正登录完成或读到好友数据。而只是表示你已经向服务器发送了这样的请求(如果异步发送模式,则还不一定请求发送完成),这时候服务器给你的返回时机取决于服务器当时的负载状态以及网络的优劣。这个时间是我们不能控制的,因此我们只能返回等待。并且在等待过程中还要处理一些其它的返回消息。而登录操作,而会更慢,因为你别看你只是调用了一个接口,实际上它内能还是做了很多事情,比如请求登录令牌,如果是重定向登录,而需要重定向到目标服务器,而后才发送登录包,最后才是接收处理登录成功包。所以这里是要花很多的时间的。
  2. 我们在开发这样的开发包时,并不会合并多个不同操作的子接口。比如:登录接口,就只处理登录操作,而不会随便去帮你读取好友,读取在线好友等。这里都应该用下游的开发人员来完成。但是在开发包里面为了要完成一定的功能,则必须要合并一个操作(连接发送多个包),比如要登录,那么首先要发送请求登录令牌包,在接收到登录令牌后才真正发送QQ号和密码,进行登录,在接收到登录返回信息后还要根据是否需要重定向登录而再决定之后操作。

也就是上面的两个问题决定了你这段代码是无法返回正确结果的。

而在使用场合上,有一些朋友希望能用这个开发包开发WEB版本的QQ,或是使用Silverlight开发Silverlight平台下的QQ通信工具。这些从理论上来说,都是没有问题,但是由于它在接口处理方式上与普通的Web模式有很大的不同。也就是你的Web客户端请求了一个命令后,你是不可能像查询数据库那样给它即时返回消息结果的。这时候就必须解决一个问题,就是服务器在收到QQ服务器返回的消息时如何第一时间通知你的WEB客户端,你可以使用客户端轮循的方式或是其它更为优良的办法来让你的WEB客户端及时得到服务器希望向你发送的消息。这个已经超出我们这个开发包所要涉及的范围了,所以这些问题你必须想办法得到解决。

还有一位叫luna的朋友问关于它为什么不能得到它的好友信息,代码如下:

   1: WL("共得到{0}位好友", e.QQClient.QQUser.Friends.Count);
   2: for (int i=0;i<=e.QQClient.QQUser.Friends.Count-1;i++)
   3: {
   4: WL("第"+(i+1).ToString()+"位好友:"+e.QQClient.QQUser.Friends[i].BasicInfo.Nick+"("+e.QQClient.QQUser.Friends[i].BasicInfo.QQ.ToString()+")");
   5: } 

如果你仔细去看一下FriendList的定义,它是从Dictionary<int,FriendInfo>继承下来的一个Dictionary子类。而由于它的Key类型是int,这个Key的值是用户的QQ号码。也就是用QQ号码来标识每个用户的信息,这是为了后面更新信息时方便才这样做的。面你的这段代码里面是按下标也读取的,而下标值刚好也是Int类型,编译没有问题,但是运行时就出错了。所以你的代码改成这样就可以了:

   1: int i = 0;
   2: foreach (FriendInfo info in e.QQClient.QQUser.Friends.Values)
   3: {
   4:    WL("第" + (i++).ToString() + "位好友:" + info.BasicInfo.Nick + "(" + info.BasicInfo.QQ.ToString() + ")");
   5: }

具体接口的使用就不多做介绍了,还是自行多揣摩吧。另外,今天还要感谢Midapex Village修改了一个关于在线好友的问题。从今天开始这个开发包正式更名为LumaQQ.NET,还希望大家有什么问题到LumaQQ.NET去讨论吧。

posted on 2008-03-14 20:39  阿不  阅读(9098)  评论(19编辑  收藏  举报