阅读更多
1 说在前面
本文是面向程序设计的初学者和喜欢DIY的朋友,主要目的就是教读者用VC++实现一个简单的QQ客户端,因为比较简单,被作者成为 QQ1986。如果只是想使用QQ的话,自己动手做的,肯定没有腾讯官方的好, QQ1986什么高级功能都没有,可以说是垃圾产品,所以本文仅当娱乐用途…
看懂本文,你需要掌握的知识:Windows编程,VC & MFC,以及一定的网络和多线程编程基础.
转载请保留版权和链接 ┟ 湘生福地 ┦www.Az86.cn,任何问题请联系
[email protected]
1.1 QQ版本
腾讯的协议在不断更新,但一些比较经典的协议仍在使用比如2005,这里编写的QQ客户端使用的就是2005版本的QQ协议。因为2005版的大部分协议已经非正常的公开,我们可以省去枯燥的协议分析步骤。
1.2 界面
为了简单起见,略去了QQ的那些界面,将其整合在一个对话框内。
1.3 主要功能
只提供基本功能哦,登陆,下载好友,发送和接收文本消息,当然通过学习本文后,你可以参考公布的2005协议,自己添加想要的功能, 如文件传输,视频等等。
2. 系统设计
整个系统从基本功能上讲可以分为三个过程,登陆,聊天,退出,因为退出在程序关闭后会与服务器自动断开,这部分功能被省略。
对一个Windows网络通讯软件来说,系统又可以分为交互界面,控制主程序,网络通讯等三大模块。而各个模块的设计,是根据基本功能的需求来决定。这里系统设计主要是指这交互界面,控制主程序,和网络通讯模块的设计。
2.1交互界面
登陆模块,对交互界面的需求有:选择网络,用户输入用户名和密码,和登陆按钮。
聊天模块,对交互界面的基本需求有:好友列表,发送消息框,接受消息框,以及发送按钮。
退出模块,被省略。
从上面的描述看,我们对界面的要求变得比较明朗,总结如下:(参考界面发布的图像)
l 一个Combo Box来选择网络
l 两个Edit Box 用作输入用户名,密码
l 一个List Box 来显示好友
l 两个Edit Box 用来显示消息和输入消息
l 两个Button 一个用来登陆,另一个用来发送消息
l 若干Static text 来显示固定的文本和系统信息
当然你可以使用 Tree control 控件来显示好友,rich edit box来输入和显示消息,那样界面会更友好,本文为了简单起见略去。
2.2 网络通讯
简单起见,在这里仅使用UDP协议。
用两个消息队列,一个用来发出消息,一个用来接收消息。
一个发送消息函数,从发出消息队列中取出一个消息,并发送。
一个接受消息函数,从网络中接收消息,并发送到接收消息队列中。
2.3 控制主程序
主程序是本文的重点部分,主要介绍线程及其函数,程序模块等.
2.3.1 主要线程介绍
主程序共分为四个线程,一个线程发送消息,一个线程接收消息,一个线程处理消息,一个控制界面和主流程。
发送消息线程,调用网络通讯模块中的发送消息函数。
接收消息线程,调用网络通讯模块中的接收消息函数。
处理消息线程,调用接收消息处理函数。
主线程,响应界面和控制流程。
2.3.2 系统框架
整个系统框架分为两部分,登陆和聊天。
登陆部分:
Step1 向服务器群发登陆请求
Step2 收到服务器回应,向服务器请求登陆令牌(logintoken)
Step3 收到登陆令牌,发送登陆请求,如果成功则返回一个会话密钥(Session Key),以后的通讯就靠它加密,解密;如果服务器满员,将收到一个重定向到其他服务器的包(package),里面包括服务器的IP和端口号,返回Step1。
Step4 向服务器请求下载个人资料。
Step5 向服务器请求下载好友列表。
聊天部分:
聊天可简单的分为发送消息和接收消息。
发送消息,将要发送的内容打包成消息协议的格式发送,等待回执,如果0.5秒没有响应,重复发送该消息。
接收消息,从网络中接收消息包,回复一个回执包,解密接受到的消息包,并显示在消息框内。
3. 具体编码实现
3.1 选择网络
本部分请参考本站文章,在VC++6.0中调用GetAdaptersInfo枚举网卡。
3.2 网络通讯底层,UDP协议
本部分比较简单,用Windows Soket创建数据报(UDP)套接字,使用recvfrom和sendto 接收和发送消息,详细过程略去,请参考源代码
3.3 加密算法
整个过程采用的加密算法有一个非对称的MD5和对称的TEA。
3.3.1 MD5
请参考 http://baike.baidu.com/view/7636.htm
3.3.2 TEA填充加密算法
腾讯虽然采用了标准的TEA算法,但对采用了交织及随机填充随机数的技术。具体请参考《TEA算法在QQ中的应用》
3.4 通讯协议
请参考LumaQQ 2005
3.5 流程控制
QQ1986为了方便,将所有整个流程分为若干状态,当处于某种状态时,由主线程来指挥做具体的事情。
这些状态分别为:
QQ_ZERO 零状态,即启动程序时的初始状态
QQ_START 程序初始化,已经启动各个需要线程
QQ_PREFIRST 初次向服务器发送登陆请求
QQ_WF_PREFIRST 等待服务器返回处理的初次发送登陆请求
QQ_REDIRECT 重定向
QQ_WF_REDIRECT 等待系统返回处理的重定向请求
QQ_LOGINTOKEN 请求登陆令牌
QQ_WF_LOGINTOKEN 等待系统返回处理的请求登陆令牌
QQ_LOGIN_IN 登陆服务器
QQ_WF_LOGIN_IN 等待系统返回处理的登陆服务器
QQ_PRE_ONLINE_FIR 请求下载个人资料
QQ_WF_PRE_ONLINE_FIR 等待系统返回个人资料
QQ_PRE_ONLINE_SEC 请求下载好友列表
QQ_WF_PRE_ONLINE_SEC 等待系统返回好友列表
QQ_ONLINE处于已登陆,可以聊天状态