自从博客园闪存发布了QQ机器人以后闪存数量一下子就上升了很多很多人也一直都在询问QQ机器人是如何开发的这足以说明QQ在中国不仅仅是普通人使用的IM工具在程序员圈子里也相当有人缘的其老大地位不容怀疑啊我这篇也算是给解答一些朋友的疑惑吧 所谓的IM机器人(QQMSN)其实就是一个简化版的IM客户端(QQMSN)利用这个简单的客户端连接到IM服务器接收和发送消息来达到自动回复的目的可惜NET中并没有开源的QQ机器人的开发包(MSN有DotMSN详见《使用DotMSN 开发MSN机器人》)博客园使用的是商业组件而对大部分人来说更希望是免费的NET中没有开源开发包但是JAVA中却有在Liunx等其它非Windows平台下会有很多的开源QQ其中的LumaQQ也算是比较有名的开源QQ了你可以从它的官方主页上了解更多的信息在网络上也已经有人根据LumaQQ的协议使用C#来开发机器人了遗憾的是没有一个是开源的没有也罢那我们就直接使用JAVA版本来的LumaQQ来开发自己的机器人吧 其实使用JAVA语法对于我们来说并不是一件难事我想大家主要的麻烦就在于如何去使用JAVA的开发工具引用LumaQQ的包以及编译调试打包和部署但这些在这里都不是难事我会提供引用好了点整个的Eclipse解决方案(工作空间)你下载了直接在这个空间下开发编辑源代码即可下面先来说说简单的原理 原理部分这个机器人我们直接开发一个一直运行的机器人即可如果你对JAVA本身并不是很了解的话那么我建议QQ机器人本身只提供一个QQ客户端收发信息的作用并不将机器人逻辑写在这个机器人客户端里面把机器人逻辑写到一个WebService中一方面你可以用你最擅长的语言来开发WebService一方面如果你需要多种平台的机器人(MSN机器人等)这部分的逻辑是可以公用的而不需再次去开发测试这部分 代码部分关于LumaQQ接口开发机器人网上已经有很多的代码了我也是从网上直接拷贝的代码下来的最关键的代码有以下两部分 CODE 设置参数登录代码 : private void connect() : { : try : { : client = new QQClient(); : clientaddQQListener(this); : clientsetConnectionPoolFactory(new PortGateFactory()); : user = new QQUser( qqrobot); : usersetStatus(QQQQ_LOGIN_MODE_NORMAL); : : clientsetUser(user); : //TCP登录 : usersetUdp(false); : clientsetTcpLoginPort(); : clientsetLoginServer(); : //UDP登录 : //usersetUdp(true); : //clentsetLoginServer(); : : //clientsetProxyType(Socks); : // clientsetProxy(new InetSocketAddress(AF)); : : clientlogin(); : } : catch (Exception ex) : { : exprintStackTrace(); : //clientrelease(); : } : } 分代码里面提供了两种方式TCP和UDP来登录到服务器大家都知道QQ直接这两种方式的登录但是需要使用不同的服务器地址 CDOE 事件处理代码 : public void qqEvent(QQEvent e) : { : switch (etype) : { : case QQEventQQ_LOGIN_SUCCESS: : msg(QQ_LOGIN_SUCCESS); : break; : case QQEventQQ_LOGIN_FAIL: : msg(QQ_LOGIN_FAIL); : msg(reconnect); : connect(); : // clientrelease(); : //Systemexit(); : break; : case QQEventQQ_LOGIN_UNKNOWN_ERROR: : msg(QQ_LOGIN_UNKNOWN_ERROR); : msg(reconnect); : connect(); : // clientrelease(); : //Systemexit(); : break; : case QQEventQQ_LOGIN_REDIRECT_NULL: : msg(QQ_LOGIN_REDIRECT_NULL); : msg(reconnect); : connect(); : // clientrelease(); : //Systemexit(); : break; : case QQEventQQ_CONNECTION_LOST: : msg(QQ_CONNECTION_LOST); : msg(reconnect); : connect(); : // clientrelease(); : //Systemexit(); : break; : case QQEventQQ_NETWORK_ERROR: : msg(QQ_NETWORK_ERROR); : msg(reconnect); : connect(); : // clientrelease(); : //Systemexit(); : break; : case QQEventQQ_CONNECTION_BROKEN: : msg(QQ_CONNECTION_BROKEN); : msg(reconnect); : connect(); : // clientrelease(); : //Systemexit(); : break; : case QQEventQQ_RECEIVE_TEMP_SESSION_IM: : SimpleDateFormat tempDate = new SimpleDateFormat(MMdd HH:mm); : impacket = (ReceiveIMPacket) egetSource(); : qqnum = impackettempSessionIMsender; : immsg = new String(impackssage); : msg([ : + tempDateformat(new Date(impackettempSessionIMtime)) : + ] + qqnum + : + immsg); : addFriend(qqnum); : msg(临时回复); : clientsendIM(qqnum UtilgetBytes(对不起: + impackettempSessionIMnick + GK助手暂时还不支持临时会话请先将我加为好友然后在正常聊天窗体与我聊天这样我才能帮助你:))); : break; : case QQEventQQ_RECEIVE_NORMAL_IM:// 收到正常消息;? : SimpleDateFormat sdf = new SimpleDateFormat(MMdd HH:mm); : impacket = (ReceiveIMPacket) egetSource(); : qqnum = impacketnormalHeadersender; : immsg = new String(issageBytes); : msg([ : + sdfformat(new Date(impacketnormalHeadersendTime)) : + ] + qqnum + : + immsg); : if (impacketnormalIMreplyType != QQQQ_IM_AUTO_REPLY) : { : msg(好友: + qqnum +请求信息: + immsg ); : clientsendIM(qqnum UtilgetBytes(immsg)); : } : //if (immsgtrim()equalsIgnoreCase(exit)) : // { : // Systemoutprintln(qqnum + 命令你;退出); : // clientlogout(); : // clientrelease(); : // Systemexit(); : // } : break; : case QQEventQQ_ADDED_BY_OTHERS:// 事件发生在有人将我加为好友时 : case QQEventQQ_ADDED_BY_OTHERS_EX:// 事件发生在有人将我加为好友时 : msg(QQ_ADDED_BY_OTHERS_EX); : snpacket = (SystemNotificationPacket) egetSource(); : qqnum = snpacketfrom; : msg(qqnum + 把我加为了好友;?); : clientsendIM(qqnum UtilgetBytes(hello)); : break; : case QQEventQQ_REQUEST_ADD_ME:// 事件发生在有人请求加我为好友;? : case QQEventQQ_REQUEST_ADD_ME_EX:// 事件发生在有人请求加我为好友;? : msg(QQ_REQUEST_ADD_ME_EX); : snpacket = (SystemNotificationPacket) egetSource(); : qqnum = snpacketfrom; : msg(qqnum + 想加我为好友;);// : clientapproveAddMe(qqnum); : addFriend(qqnum); : break; : case QQEventQQ_ADD_FRIEND_NEED_AUTH: : AddFriendExReplyPacket packet = (AddFriendExReplyPacket)egetSource(); : qqnum = packetfriendQQ; : sendAddFriendAuth(qqnum); : break; : case QQEventQQ_REQUEST_ADD_OTHER_APPROVED:// 事件发生在有人请求加我为好友时我同意并且加他为好友 : msg(QQ_REQUEST_ADD_OTHER_APPROVED); : break; : case QQEventQQ_REQUEST_ADD_OTHER_APPROVED_AND_ADD:// 事件发生在有人请求加我为好友时我同意并且加他为好友 : msg(QQ_REQUEST_ADD_OTHER_APPROVED_AND_ADD); : break; : case QQEventQQ_REQUEST_ADD_OTHER_REJECTED:// 事件发生在我请求加一个人那个人拒绝;? : snpacket = (SystemNotificationPacket) egetSource(); : msg(snpacketfrom : + 拒绝加我为好友;?理由为 : + ((ssage == null || ssage : equals()) ? ;? : ssage)); : break; : case QQEventQQ_KICKED_OUT_BY_SYSTEM: : msg(QQ在别处登录了重新登录); : connect(); : break; : default : : msg(etype); : break; : } : } 大家看到了LumaQQ里面的事件处理看起来似乎比较原始了一点但是没关系它是确实可用的LumaQQ里面支持的QQ事件协议都在QQEvent中已经有定义了同时不同的事件它的事件参数egetSource()都是不同类型的对象比如接收到正常消息它的事件枚举是QQEventQQ_RECEIVE_NORMAL_IMegetSource()的类型是ReceiveIMPacket你把这个对象转换成ReceiveIMPacket类型后就可以得知是谁发送的什么样的消息了这时候你就可以调用clientsendIM方法来回复消息了至于回复什么就是你的机器人要做的事件了它里可以调用WebService也可以把业务逻辑直接写在这边 还有就是断点重连LumaQQ已经可以保证长时间在线了但是我们也要有断线重连的功能这个在例子中也已经有了还有其它的事件和接口我就不详细介绍了因为我个人对JAVA的了解也不够多下面再来介绍一下Eclipse的打包吧这也是一个比较麻烦的地方没有同事的帮忙我也是一时半会儿也搞不定 编译打包部分同事给我的是装有ObjectWeb Lomboz插件的eclipse我还必须要说明一下我的eclipse目录是在D\Program Files\ecplise 因为它有可能影响到一些包的引用和编译它的启动界面是这样的 图一 大家下载完附件的示例代码后在文件菜单下点击Switch Workspace选择解压后的目录就可以打开解决方案了(工作空间)里面会有三个工程LumaQQ是QQ协议工程 是LumaQQ负责网络连接部分的工程代码robot是QQ机器人工程如果你要在eclipse里面运行或调试机器人点击QQRobotjava右键在菜单中选择RunAs或DebugAs Java Applcation就可以运行或调试了 图二 更多的调试技巧我就不多介绍了下面来介绍打包吧eclipse要打包成控制台程序那也不是一件容易的事情要先将这个解决方案导出成jar包File Export 选择Java目录下的JAR File 图三 把三个工程都选择起来选择包存放的路径和包的文件名 图四 一路Next或者直接Finish可能是弹出警告提示看不懂也不用管它转到你刚才包的保存路径正常情况下你可以看到你刚才保存的文件名jar这么一个文件接下来的工作就是把这个jar打包成exe控制台程序了这还得借助于另一个工具的帮忙我使用的是exej你从网络上去下载就可以了不过它是共享软件非注册版本打包的exe在运行前会弹出一个提示告诉你是这个exe是用什么打包的宣传一下有点讨厌 打包exe需要创建exej的工程文件还有一个麻烦的就是要指定它所引用的所有第三方包的路径而且设置输出路径版本运行环境等等这么信息为了方便起见我也把这个文件放在附件的示例中了安装了exej后就可以打开这个文件了打开了点击Finish就在编译了 图五exej工程文件 图六引用的第三方包 图七编译中 经过这一系列的步骤后你所得到的exe文件就是一个可用的控制台程序了这时候除了JRE外不需要其它的插件的支持了 写在最后做为一个NET平台的开发人员以上的步骤对我们来说确实是太过于烦杂了在寒冬季节我写这样的一篇文章都快要满头大汗了我相信各位看官如果能坚持看到这里那么你一定是非常有耐力了但是没有办法我们需要忍受如果有时间有精力我还是很愿意以LumaQQ为样本开发一个开源的QQ开发包这样大家就不用再这么麻烦了 |