免费vc++网上寻呼QICQ源代码附带论文(一)

时间:2022-11-22 17:30:39 计算机毕业论文 我要投稿
  • 相关推荐

免费vc++网上寻呼QICQ源代码(附带论文)(一)

第 1 章  概论

免费vc++网上寻呼QICQ源代码(附带论文)(一)

§1.1 课题的来源及意义
 
 在网络无所不在的今天,在Internet上,有icq,oicq,ticq等网上寻呼软件,极大程度上方便了处于在世界各地的友人之间的相互联系,也使世界好象一下子缩小了,不管你在哪里,只要你上了网,打开这些软件,就可以给你的朋友发信息,不管对方是否也同时在线,只要知道他有号码。
 
 现在,企业、机关、学校都建立起了自己的局域网,在局域网,虽然可以通过文件共享的方式进行通讯,但单单使用这种方式,是非常不方便的,首先,在局域网里的网上邻居里,只能看到机器名,不清楚对方是谁,也不知道对方机器里有什么资源可以共享,而且,当局域网的机器很多时,这种方式更加麻烦。于是,就想到做一个在局域网里的icq,在局域网里,我们可以通过它,实现在局域网里方便的联络,进行文件传输,消息的发布,自己共享内容的简介等。在学校建立起校园网里,这软件可以起到方便同学之间,教师之间,师生之间的相互联络,这样,不用上Internet,可以节省资源,在学校这个大环境里,就可以同学之间联系,联络感情,促进同学之间的友谊,学生可以通过它来与不同寝室的同学,教师讨论问题。并能最大限度地利用现有的网络资源,极大地提高工作效率。为了适应校园网的建设,实现校园网内进行消息发布,学生交流,师生交流,网上作业等功能。


§1.2 网上寻呼的软件的现况
 网上寻呼软件在国外的有icq等,在国内的主要有腾讯的Oicq,还有Ticq,OmO和一些在网页上的即时通讯工具,像Chinaren网站上的WebMaster等等,都做得即美观,且功能强大,Oicq现在拥有非常大的用户群。
 
 在局域网内的网上寻呼,就我知道的有武汉硕思软件公司的硕思即时通,能够较好的完成局域网上寻呼,聊天,发文件,收E-mail等功能。
 
 现在也有很多,在局域网上不使用服务器的通讯软件,这种软件小巧且方便,也能解决一部分问题。但是有服务器的通讯软件,有着不可比拟的优势:可以发送离线消息,不管用户当时是否在线,下次上线时,就可以看到这条消息了。可以保存用户的个人信息或介绍,供人查看。而且,那种通讯软件,是以机器为通讯单元的,而这种寻呼软件是以人为通讯单元。总之,这种软件在局域网上,还是有很大的用途的,为局域网上通讯,带来极大的方便。
 
虽然说,现在这个软件已经有公司把它开发出来了,我再做也不一定有新意,也未必可以做得更好,但作为毕业设计,也算是对我能力的一个考验和这四个我学习知识的一个检查。而且,我校现在也正在筹备建立校园网,如果这个软件做得比较成功的话,能为校园网上的通讯带来一定的方便,我就很满足了。
 
 
 
§1.3面向对象方法与设计简介
 
 传统的软件工程方法有生命周期方法和快速原型法。
 面向对象方法学是一种全新的软件工程方法,其出发点和基本原则是尽可能模拟人类习惯的思维方式,把构成客观世界的实体抽象为对象。概括地说,面向对象方法学有四个要点:
 1.认为客观世界是由各种对象组成的,复杂的对象可以由比较简单的对象以某种方式组合而成;
 2.把所有对象都划分成各种对象类,每个对象类可以定义一组数据和方法;
 3.按照子类和父类的关系,把若干对象类组成一个层次结构的系统;
 4.对象彼此之间仅能通过传递消息互相联系。
用面向对象方法学开发的软件有以下优点:
1.与人类习惯的思维方法一致;
2.稳定性好;
3.可重用性好;
4.可维护性好。
 
 
§1.4本章小结
 随着计算机应用技术的日益普及,网络也遍及到我们生活的每个角落,很好的利用这人资源,将为我们的工作和学习,带来极大的方便和提高工作效率,所以,开发一个局域网里的C/S通讯软件,是十分必要。
 由于采用面向对象方法开发软件具有明显的优点,本系统将采用面向对象方法进行开发。由于采用面向对象的系统模型可以使整个软件系统的结构变得更加灵活,本系统的结构模型将采用面向对象的系统模型,采用VC++6.0这个可视化开发工具进行编码。
 


第 2 章  网络通讯程序的设计原理和过程
 
 对网络通讯程序的设计的原理和过程的透彻理解,是网络通讯程序的前提。本章将简要地介绍一下有关网络通讯程序设计的基本知识。
 
§2.1 TCP/IP协议
 TCP/IP是国际互联网所采用进行网际互连的通信协议。实际所称的TCP/IP协议包括了在国际互联网上应用的一组协议,互联网协议族是此协议族的另一个名字。这个协议族包括几种工作在不同层次上的网络协议,IP互连协议(Internet Protocol),负责主机之间的传输数据。TCP传输控制协议(Transmission Control Protocol),负责在应用程序之间传递数据。UDP用户数据报协议(User Datagram Protocol),提供给用户进程的无连接协议,也负责在应用程序之间无连接传递数据,但不执行正确性检查。ICMP互连网控制报文协议(Internet Control Message Protocol),处理主机间的差错和传送控制。ARP地址解析协议(Address Resolution Protocol),负责将网络层地址转换成链路层地址。RARP反向地址解析协议(Reverse Address Resolution Protocol),负责将链路层地址转换成网络层地址。
 
 TCP/IP协议的核心是传输层协议(TCP、UDP)、网络层协议(IP)和物理接口层,这三层通常在操作系统的内核中实现。TCP/IP网络环境下的应用程序设计是通过网络系统编程界面Socket实现的,Socket提供应用程序与系统内核之间的网络编程接口。协议可以是可靠的可以是不可靠的。可靠的协议意味着当数据通过协议传递时,协议保证数据正确传输。可靠传输包括几个特征。首先,为了确保数据正确传送,协议在通信应用程序之间互相交换确认信息。也就是说,程序每次发送-个报文时,都期望对方发送一个相当于说:“我得到这个报文”的确认信息。如果发送程序没有收到这样一个确认信息,程序将自动重新发送此报文,直到得到应答信息为止。其次,为了确保传输的数据有效,可靠协议在每次传输时,都包含一个或更多的校验和(CRC)。接收计算机重新计算校验和,与收到的校验和进行比较。如果不匹配,就表明在传输过程中发生了错误。
 
 传输控制协议TCP是一个使用校验和、确认信息以及其它可靠数据传输技术的可靠协议。相比之下,不可靠协议不能确保数据正确传输。协议试图传输数据,但不保证成功。而且,不可靠协议在传输失败后,并不通知发送方应用程序。可将不可靠数据传输比作没有返回地址的信件。如果发送地址是锗误的,由于邮递系统不能将信退回给你,所以你就不知道信件有没有送到。即使发送地址是正确的,也不能保证邮递系统不丢失你的信件。
 
 TCP/IP协议组中存在的两个基本数据服务是:字节流服务和数据报服务,使用字节流的协议将信息看作一串字节流进行传输。协议不管要求发送或接收数据的长度和传送数目,只是将数据看作一个简单的字节串流。使用数据报的协议将信息视作一个独立单元进行传输。协议单独发送每个数据报——数据报之间不相互依赖。例如,假设你使用字节流协议发送5个数据段(每个有10字节)和一个包含50字节的数据段(总共100字节)。连接的接收方可以按每次20字节读数据(要读5次)。传输控制协议是字节流协议。
 
 字节流协议不关心每个数据段的长度。如果应用程序使用字节流协议发送数据,则协议能够保证连接的另一端按照发送的顺序接收数据。相比之下,传输到同一目的地的多个数据报可能不会按发送顺序到达。如果接收方应用程序要求数据顺序一致,应用程序必须在数据到达后,校对这些数据。用户数据报协议和互连网协议使用数据报传输数据。数据报类似于信件。如果你在同一天给同一个人邮寄两封信,你无法知道那个人先收到那封信。同样,如果连续两天给两个人邮信,你也不能知道哪封信先收到。收到信的顺序和发送顺序可能相反。

 在TCP/IP术语中,端口类(Port)似于IP地址,IP地址与主机地址是相联系的,端口和协议相联系。IP数据报保存目的和源IP地址,同样传输协议也保存源和目的端口号。如果端口这个概念对你来说很陌生,请考虑计算机上的硬件端口。你可能编写过往硬件端口送数据的程序。例如为了打印,如果没有其它程序的话,必须向串或并端口发送数据。PC机给它的端口命名和编号。
 
 例如,PC机的并行打印端口称为LPTl和LPT2,串行端口称为COM1和COM2。在Internet上,网络只是简单地对协议端口编号。在PC机,LPT1表示并行端口1。成千个PC机应用程序使用此方案。多年来,程序员编写PC程序时都假定LPT1表示并行打印端口1。同样,程序员将每个Internet协议端口与一个特定的应用程序和功能联系在一起。
 
 Internet包括像FTP、Telnet和Mail这样广泛使用的应用程序采用的应用协议,在Internet上,这些应用程序使用一种叫做“通用口分配”的端口。通用口分配是特定应用程序广泛使用的一个协议端口。像PC程序员使用打印端口LPT1用于打印,Internet程序员也对具体应用程序使用许多协议端口。例如,平凡文件传输协议(FTP)的通用口分配是端口号21的。Telnet的通用口分配是端口号23。

§2.2 客户/服务器程序的设计
 
 客户机/服务器模型也是一种网络模型,但与前述的模型不同,它并不是定义了网络的层次结构,而是描述了一种网络程序运行的方式。
 
 客户及/服务器模型将网络应用程序分为客户和服务器两部分。客户方对服务器方发送信息请求,服务器方对其做出相应回答,提供服务。在TCP/IP网络应用中,多数网络应用程序是使用客户/服务器模型设计的。服务程序通常在一个众所周知的地址监听对服务的请求,也就是说,服务进程一直处于休眠状态,直到一个客户程序提出了请求信息。此时,服务程序被"惊醒"并且为客户提供服务,对客户的请求作出适当的反应。虽然基于连接的服务是设计客户/服务器应用程序的标准,但有些服务也是可以通过数据报Socket提供的。
 
 通常,网络应用程序包含两个独立的应用程序:客户程序和服务器程序。但是,也可以设计同时完成这两种功能的程序,例如,一些服务器程序如果不能完成一个服务请求时,它将转而充当客户程序,向其它服务器程序请求信息。这方面的一个典型例子就是提供Internet从域名到IP地址映射服务的DNS服务器。
 
 为了充分理解TCP/IP协议族,必须理解几个重要术语。这些术语指出了两个TCP/IP传输协议:用户数据包协议(UDP)和传榆控制协议(TCP)之间的区别。这些术语进一步描述了与网络连接、协议可靠性以及数据服务有关的协议特性。
 当建立服务器程序时,应该将服务器程序设计成等候客户的请求。你知道,TCP传输层通过协议端口和应用程序  (像服务器和客户)通信,也就是说,为了按收客户请求,服务器程序必须对传输层的一个特定协议端口进行侦听。当服务器配置socket接口时,它使用bind()函数让socket执行体登记一个协议端口。也就是说,程序告诉socket执行体使用哪-个协议端口进行数据传送。Socket执行体接着告诉传输层某个特定协议端口已被使用,并将其收到的所有数据传送给Socket API。

 使用无连接协议的程序和使用面向连接协议的服务器程序之间的主要相似之处是它们都必须对一个协议端口进行侦听。例如,无连接和连接服务器程序必须在协议端口侦听客户请求。同样,由于无连接客户程序没有和远地主机建立直接连接,所以它也必须对协议端口进行侦听,以便接收以对它服务请求产生的数据报应答。Socket API中的bind()函数让程序将一个本地地址(包括主机地址和协议端口)和一个Socket联系起来。
 下面程序行显示了一个典型的函数调用:
result=bind ( socket_handle, local_structure, socket_address, address_ length)
 无连接客户程序也对一个协议端口进行侦听。使用无连接协议的程序不和远地主机建立直接连接。无连接客户程序使用数据报发送网络服务请求,它不建立点到点连接。因此无连接客户程序必须在一个协议端口,对应答数据报进行侦听。与服务器程序一样,无连接客户程序也使用bind函数让Socket执行体登记协议端口。也就是说,类似服务器程序,无连接客户程序告诉Socket执行体使用哪个协议端口进行数据传输。Socket执行体处理传输层内UDP软件模块和客户程序之间的接口。

 

第 3 章  软件功能与界面需求
 提供基于TCP/IP网络的即时消息传送、消息广播、实时聊天、文件传输等功能。 具体列举如下:
 支持多账号
 可以同时发送同一个消息给多人,通过输入这些人的号码列表或姓名列表
 可以同时发送一个消息给所有好友
 有权限的人可以向所有用户发送“消息广播”,便于消息的发布
 即使用户不在线,也能通过服务器发送离线消息
 提供消息、聊天的历史记录,方便对信息的查看和管理
 提供查看在线的人的功能
 提供按ID或姓名查找用户的功能,添加用户方便
 小窗口显示,不占用屏幕很大的空间,
 支持热键调出后台的应用程序。
 应用程序运行后,在任务栏右边生成一个图标,单击弹出在线状态     菜单,双击显示应用程序窗口,右击弹出主菜单。
 支持隐身登陆,可以看到在线的朋友,朋友却不知道你上线了
 可以实时显示用户的状态和随时改变自己的状态
 提供了自动弹出消息
 好友上线通知
 好友下线更新
 有权限的人可以发系统广播(或在服务器上发)
 查看好友信息
 按姓名或号码查找某人
 在好友列表中删除某人
 可以选择在某人的好友中删除自己
 更改个人信息
 系统设置
 给在线好友传文件
 消息管理器
 在程序中设定最大,最小窗口尺寸(宽度,高度)
 主窗口总是浮在最上端
 速度快,占用资源少

 第 4 章  概要设计和详细设计
 
 本章将论述软件系统的面向对象设计过程。用Visual C++语言在Windows环境下编程实现。
 
§4.1总体设计概述
 采用客户端——服务器模型,使用从MFC类中的CAsyncSocket类的派生类进行实现底层通讯,底层利用UDP数据报协议进行通讯,这样,便于客户端之间的直接通讯,也可以高效的传送消息。因为使用UDP协议进行通讯,所以要自己控制其可靠性。我每发送一个数据,接受方接受到数据后,会发回一个响应信息,发送方在一个超时时间内,收到响应信息,就表示发送数据成功,若没有收到,就表示发送失败,会按用户指定的次数N,重试N次,如果N次都失败,就返回发送数据失败。当然,发回来的确认信息也可能丢失,但确认信息很短,相对来说,丢失的机率会小一些,是一个折中的办法。
 
 为了保存用户信息和好友信息及一些相关数据,服务器使用到数据库技术。服务器的数据库采用的是ODBC的ACCESS数据源,服务器访问数据库,用的是MFC中的CDatabase和CRecordset,因为,对数据库的操作简单,服务器端,我只要功能,不需做界面,所以使用Sql语句直接访问数据库,已经足够满足要求了。
 
 服务器运行的流程为:
 服务器运行后,开启服务,则服务器开始侦听用户请求,如有信息发送过来,首先,发送回确认信息,然后,建立一个线程,处理接受到的数据。在线程里,按照接受到数据的类别,进行相应的处理,如有需要,会向用户发送处理的结果,或成功或失败的消息,处理结束后,线程就结束了。这样,可以实时接受每个用户的请求,不会因为处理一个用户的请求,而忽略了其它用户。
 
 服务器端主要是为用户存储必要的信息,协调用户之间的通讯,服务器端的设计,主要在功能上面。服务器端的设计和底层通讯的方法,将是我讲述的重点。
 
 客户端的运行流程为:
 若有本地用户信息,则取出本地用户信息,显示登陆窗口,若没有,则显示用户注册窗口(在登陆窗口里,也可以选择用户注册)。登陆时,可选择是否隐身,进入系统后,好友列表中,在线的人,将以高亮度显示,并处在列表的上头。不在线的人,将以灰色显示。登陆后,如果有的话,服务器会发来好友给你发送的离线消息或广播消息。如果有好友上线了,就会通知你,好友下线了,你也可以在好友列表中看到,你可能接受到别人给你发送的消息,或广播消息等。根据用户的操作,可以向好友发送消息,查看好友信息,查看在线的人,查找用户,发送广播消息等等功能。
 
 客户端主要是提供给用户一个友好的用户界面,方便用户操作,客户端主要负责从服务器上得到数据后,显示给用户。从服务器得到好友的IP和Port后,就可以直接与好友进行通讯,聊天等等。客户端主要是界面的设计(除了底层通讯的以外),根据不同的要求,向服务器发送各种类型的请求。然后等待服务器的响应。客户端的界面的设计很繁琐,没有详细介绍的必要,所以,我的重点,将放在服务器的设计上。客户端只是简要的说明一下。


§4.2服务器数据库的设计:

 服务器数据库设计的要求是要能够满足客户端的需求,保存用户信息和用户好友信息,提供离线消息的服务,和发广播消息的服务等。总共有五个表:
 用户信息表(Users)好友信息表(Friends)广播消息表(Broadcast)离线广播表(OffBroadcast)离线消息表(OffMsg)

用户信息表(Users)
主键: UserId
UserId       自动编号            4字节长整形
Id           用户帐号            4字节长整形
Photoid      用户的图象编号      4字节长整形
password     用户登陆的密码      字符串
name      用户的姓名          字符串
sex          用户的性别       单字节整形 0 男  1 女  2 未知
age         用户的年龄     字符串 (为了适应不愿填写此项的人)
canbeadd    能否被人加为好友
//单字节整形 (0,1,2 不能被加入,允许被任何人加入,需要身份验证)
email        电子信箱        字符串
homepage    个人主页        字符串
address      地址            字符串
phone       电话            字符串 
fax          传真           字符串
department    部门           字符串
description    个人简介       字符串

好友信息表(Friends)
主键:Num
Num       自动编号           4字节长整形
MyId       自己帐号          4字节长整形
FriendId     朋友帐号          4字节长整形

广播消息表(Broadcast)
保存发送的广播消息
主键:MsgId
MsgId      自动编号           4字节长整形
SendTime    发送时间          4字节长整形
SenderId     发送者的帐号      4字节长整形
Msg        发送的消息         备注类型


离线广播表(OffBroadcast)
保存那些还没有发送广播消息的用户
主键:Num
Num       自动编号           4字节长整形
RecvId     接受者的帐号       4字节长整形
MsgId      广播消息号        4字节长整形 (对应广播消息表的MsgId)


离线消息表(OffMsg)
保存用户之间发送的离线消息
MsgId     自动编号      4字节长整形
RecvId     接受者的帐号       4字节长整形
SenderId   发送者的帐号      4字节长整形
RecvTime    接受的时间     4字节长整形
nIndex     发送消息的类型    4字节长整形
Msg       发送的消息         备注类型


§4.3类设计的总体结构

服务器的类总体结构:

一.主应用程序类
CServerApp
包含全局的数据结构

二.传送信息类
CData,CMsg1,CMsg2,CMsg3,CMsg4,CMsgChangePI,CMsgModifyPwd, CMsgOnlineFriend,CMsgPerson,CshowOnlinePeople
处理传输数据

三.SOCKET通讯类
CServerSocket,   CSendSocket,   CRecvSocket
处理底层通讯的类,与外部的接口是CserverSocket类,提供了一个简单的接口

四.其它类
CMainFrame,CServerDoc,CServerView,CSetupDlg,CAboutDlg
UserInfo结构存储在线人的信息


客户端的类总体结构:

一、应用程序类
CClientApp
包含全局的数据结构

二、传送信息类
CData,CMsg1,CMsg2,CMsg3,CMsg4,CMsgChangePI,CMsgModifyPwd, CMsgOnlineFriend,CMsgPerson,CshowOnlinePeople
处理传输数据

三.SOCKET通讯类
CClientSocket
处理底层通讯的类,提供了一个简单的接口

四.用程序框架类
CmainFrame
 处理用户界面和一些接受数据的响应,主要的处理过程都在这个类里实现。

五.对话框类
CfriendDetailDlg   显示用户详细信息的对话框类
CloginDlg       显示登陆窗口的对话框类
ClookDlg        显示查看消息的对话框类
CregisterDlg      显示注册窗口的对话框类
CsetupServerDlg   修改服务器设置的对话框
CtalkDlg         显示发送消息对话框的类
CshowBroadcastDlg   显示广播消息的对话框
CshowAddMsgDlg    显示被加为好友的信息的对话框
CmultiSendDlg     通过姓名或ID列表的向多人发送信息的对话框
CsendBroadcastDlg   发送广播消息的对话框
CsendToAllDlg      向所有好友发送消息的对话框
CModifyPIDlg      修改个人信息的对话框

六.界面类
CGfxGroupEdit,CGfxOutBarCtrl,CGfxPopupMenu
实现像OutBar和oicq样式的那种滚动分栏的界面类,从Internet,上获得的源代码,通过修改一些接口,使之更适合我的应用。提供了一个漂亮的界面。

TrayIcon类
处理在任务栏上添加.修改.删除图标的类。封闭了Window的API函数

八.全局结构:
UserInfo结构存储在线人的信息
FriendState 在好友线信息结构
SaveMsg  消息的存储结构
Sparam  传给线程的参数结构
 

§4.4服务器端的常量定义
 
 在这里,定义和申明了一些全局函数,常量,宏和全局数据结构,包括用户配置文件名,默认的参数等,总之,修改程序中的参数简单,直接修改头文件就可以了,因为所使用的数值性的参数,都在这里定义了。

#define ResponseMsg "ok"              发送数据时,发回的响应消息标志
#define SETUPFILE "config.ini"           服务器的保存配置文件
#define DEFAULT_SEND_NUM  5        默认的发送端口的数量
#define DEFAULT_DATAS_PWD ""        默认的数据源的访问密码
#define DEFAULT_DSN    "IDServer"     默认的数据源名称
#define DEFAULT_UID  ""                 默认的数据源的访问的UID
#define DEFAULT_BROADCAST_PWD "1234567890" 默认的发送广播密码
#define DEFAULT_RECV_PORT_STR "4000,4001,4002"
默认的服务器接受端口号列表
const int ListenSocketNum=10;      最大的接受端口的个数
const int SendSocketNum=15;       最大的发送端口个数
const int TimeWaitForRes=1000;     等待响应的超时时间
const int MaxUserNumber=500;      服务器端最大的用户数
const int UserIdRadix=2000;         用户帐号开始的基数(从这个基数开始增加)
const int PersonNumEveryTime=20;  请求查看在线的人时,每次最多发回的人数
const int TimerSpanServer=30000;   服务器的一个运行时间间隔,过一个这个时间间隔,服务器就检查一次,看用户是否仍然在线
const int DataBufLength=500;          发送数据的最大长度
const int MaxResponseMsgLength=20;   最大的响应消息长度
const int CheckBufLength=512;        检查发回响应的一个缓冲区长度

保存在线人的信息的数据结构
typedef struct{
 BYTE State;  //0 不在线,1 在线,2  隐身
 BYTE CanbeAdd;
 DWORD Id;
 DWORD IP;
 DWORD Port;
 DWORD PhotoId;
 CString Name;
 CString Department;
}UserOnline;   

全局函数
UINT ProcessRecvData(LPVOID param);
处理用户请求的线程服务函数
UINT CheckOnline(LPVOID param);
处理定时检查用户是否仍然在线的线程函数

服务器接受到的消息类型
#define SEND_MSG_TO_FRIEND    1   //CMsg1 index,friendId,myId,msg,time 
#define FRIEND_IDENTITY_VALIDATE  2   //CMsg1
#define ADD_AS_FRIEND            3   //CMsg1
#define FRIEND_DETAIL            4   //CMsg1
#define FIND_FRIEND_BY_ID       5   //CMsg1
#define DELETE_A_FRIEND         6   //CMsg1
#define DELETE_SELF_IN_FRIEND  7   //CMsg1选择在某人的好友中删除自己
#define ACCEPT_AS_FRIEND       8   //CMsg1响应加为好友请求反馈信息
#define REFUSE_AS_FRIEND       9   //CMsg1  响应加为好友请求反馈信息
#define ONLINE                  10   //CData index,myid
#define ONHIDE                  11   //CData index,myid
#define OFFLINE                 12   //CData index,myid
#define MULTI_SEND_MSG          13   //CMsg2
#define APPLY_SHOW_ONLINE       14   //CMsg3  请求查看在线的人
#define TEST_BROADCAST_PWD     15   //CMsg4 index,id,broadcastpwd,msg 
#define SEND_BROADCAST          16   //CMsg4
#define FIND_FRIEND_BY_NAME     17   //CMsg4 index,myid,name(msg)
#define CHANGE_PERSONAL_INFO   18   //CMsgModifyPI
#define CHANGE_PASSWORD        19   //CMsgModifyPwd
#define HAVE_ID_LOGIN        20   //CMsgModifyPwd index,id,pwd(oldpwd)
#define APPLY_ID_LOGIN       21   //CMsgPerson

客户端接受来自服务器发送的数据
#define RE_ADD_AS_FRIEND           31  
//CMsg3 index,myid,value(0,1,2,3)(别人拒绝,成功加入,要求验证人份,此人已经为好友)
#define RE_TEST_BROADCAST_PWD    32  
//CMsg3 index,myid,value (0,1) 密码错误,密码正确
#define TOTAL_ONLINE             33  
//CMsg3 index,myId,Value 响应发送的总在线人数信息
#define RE_LOGIN_INFO            34  
//CMsg3 index,myid,value (0,1,2) 帐号不存在,密码错误,OK
#define RECV_SHOW_ONLINE     35 CshowOnlinePeople 回复查看在线的人
#define FOUND_FRIEND_BY_NAME 36 CshowOnlinePeople按姓名查找返回结果
#define APPLY_ID_OK              37  
//CData index,myid(收到这个信息,这表示申请帐号成功,且已登陆)
#define ID_NOT_FOUND_BY_ID     38   //CData   按号码查找,没找到
#define NAME_NOT_FOUND_BY_NAME  39  //CData  按姓名查找,没有找到
#define REQUIRE_IDENTITY_VALIDATE 40  //CData   需要身份验证
#define ONHIDE_OK            41   //隐身登陆成功
#define ONLINE_OK            52   //上线成功
#define FOUND_FRIEND_BY_ID  43  //CMsgPerson按号码查找,返回查找结果
#define RE_FRIEND_DETAIL     44  //CMsgPerson   回复查询好友信息的请求
#define ALL_FRIEND_ID         45  //CMsg2 收到这个信息,这表示登陆成功
#define ONLINE_FRIEND         46   //CMsgOnlineFriend
#define BE_ADDED_AS_FRIEND   47   //CMsg1 响应好友加入的消息
#define SYSTEM_BROADCAST     48   //CMsg1  发送系统广播


§4.5客户端的常量定义

 在这里,定义和申明了一些全局函数,常量,宏和全局数据结构,包括用户配置文件名等,总之,修改程序中的参数简单,直接修改头文件就可以了,因为所使用的数值性和可变性的参数,都在这里定义了。
 
#define WM_RECIEVE_MSG  WM_USER+104  
 //客户端接受到数据后向父窗口发送的消息
#define WM_SENDINTHREAD_RES  WM_USER+105
 //调用在工作线程中发送数据时,发送后向窗口发送的反馈消息
#define WM_SHOW_FRIEND_DETAIL WM_USER+106
 //发给CfriendDetailDlg对话框的一个消息,让它显示指定人的详细资料,传入的参数中WPARAM 是需要显示的人的UserInfo数据的指针,LPARAM是FriendState数据的指针.
#define WM_RECVMSG WM_USER+ 107
 //发给ClookDlg对象框的一个消息,让它显示别人发来的信息窗口,一有数据传到,就向它发送这个消息即可,就会显示一个查看消息的对话框,接口简单。传入的参数中WPARAM 是需要显示的人的UserInfo数据的指针,LPARAM是FriendState数据的指针.
#define WM_SEND_MSG  WM_USER+108
 //发给CtalkDlg对象框的一个消息,指示我要对指定对象发送消息,只要向其对象框对象发送这个消息,就会打开一个发送消息的对话框,不需知道内部细节。传入的参数中WPARAM 是需要显示的人的UserInfo数据的指针,LPARAM是FriendState数据的指针.
#define ResponseMsg "ok"  //确认信息串
#define USERFILE "users.db"   //保存用户的好友信息的文件
#define MSGFILE  "msg.db"     //保存用户聊天记录的文件
#define ALLUSERIDFILE "client.cfg"
 //客户端的一个记录所有登陆帐号的文件
#define USERSETUP "config.dat"    //客户端的一个配置文件
#define FACEINIFILE "face\\face.ini"  //头像文件的记录文件

在这里略去与服务器相同的:
const int TimeWaitForRes=3000; 发送数据超时时间
const int PersonNumEveryTime=20;查看在线的人,每次发回的多少人
const int TimerSpanClient=40000; 客户端每隔这个时间,若没有收到TOTAL_ONLINE消息(所有在线人数),就判断客户端已经掉线了。
const int DataBufLength=1000;  发送接受数据最大长度
const int MaxResponseMsgLength=20;
const int UserFileReservedLength=20;
 //用户user.db文件中,前面保留的字节数,以备以后扩充使用
const int MaxPasswordLength=16;密码的最长长度
const int LimitMaxMsgLength=900;限制每次发送消息的字节数
const int AutoSaveTime=200000; 自动保存用户信息的间隔时间
const int CheckBufLength=128; 检查确认信息的缓冲区长度

必要的类申明,否则以下几个数据结构会有编译错误
class CData;
class CMsg1;
class CMsg2;
class CLookDlg;
class CTalkDlg;
class CFriendDetailDlg;
class CClientSocket;
在客户端保存用户详细信息的数据结构
struct UserInfo{
 BYTE HaveDetail; //(0 没有详细资料, 1 有)
 BYTE CanbeAdd;
//能否被加入的标志(0拒绝所有,1允许任何,2需要身份验证)
 BYTE Sex;
 DWORD Id;
 DWORD PhotoId;
 char Age[10];
 char Name[20];
 char Phone[20];
 char Email[30];
 char Fax[20];
 char Homepage[40];
 char Address[60];
 char Department[20];
 char Description[100];
 UserInfo();  //对各个成员进行初始化
};

//保存消息的数据结构
struct SaveMsg
{
 DWORD ID;
 CTime Time;
 CString Msg;
};

 保存好友的在线、收发的消息、在线的IP和Port以及发送消息、查看消息、好友详细信息的窗口的指针等一些相关信息的数据结构,这些都是运行时的数据结构,不需要存储的数据。对话框都是无框式对话框,所有,必须保存各个对话框的指针。
struct FriendState
{
 FriendState();//做必要的初始化操作
 ~FriendState();//删除动态产生的数据
 BYTE OnlineState;  //(0,1,2 离线,在线,隐身)
 DWORD IP;  在线的IP
 DWORD Port; 在线的Port
 CArray<SaveMsg*,SaveMsg*>aMsg; 收发的消息列表
 int nCu这个算法即麻烦,又易出错,真不知当时是怎么想的。
现在的算法是:
 设一个缓冲区长度为N,然后,为每一次数据进行统计,发一次,就加1,然后把发送数据中的This=count%N,且把缓冲区中第This个成员设为0,在发送端,就要数组中的第This个成员是否为1即可,在接受到的确认信息中,取出This项,再为缓冲区中第This项设为1,这样就可以快速且可靠的判断发送数据是否得到响应回来了。
 
五月二十日
今天发生了一个怪事,我在调试程序时,发现在,不能在服务器的消息处理消息和OnTimer里面写发送数据的代码,否则,怎么都发送不成功,
好像它是非得此消息处理函数或OnTimer执行完毕,才让其它线程运行,我的发送函数,总是得不到正确结果,我一度怀疑我的底层通讯算法的合理性。后来,我也不知道如何解决,感觉是一个无法逾越的问题,非常失落…………………………………………
晚上,当我重新拿起来的时候,试了试,又觉得这不是不可逾越的问题,只要回避那种情况,就可以了。
我把在OnTimer里处理的事情放在一个线程里去做,完成同样的功能,现在,检查人是否仍然在线的函数,现在终于又成功了。真是太高兴了。
可是,我可能没有足够的时间来完成这个程序了。真可惜。我必须开始写论文了,否则,我将无法完成任务。

五月二十一日
今天,查到用LoadImage()函数,可以读取存在磁盘上的图象文件,客户端显示的头像的问题,终于可以解决了。可是又遇到了问题,我有32x32的16位色的图象,显示时,不知道如何使其透明背景色,因为图象有背景色,所以显示时,看上去无法与背景一样的颜色,而且,我不知道如何由32x32的图象列表,得到相应的16x16的图象列表,因为我需要以小图标的样式显示。我该如何做呢?有人帮我就好了。

五月二十二日
在客户端,我的界面用的是在网上找到的一个源代码
CGfxOutBarCtrl类,可以实现象OutLook和Oicq的那种滚动的分栏条,今天终于看懂了接口部分代码,可以随意更改为我用了。

五月二十四日
今天,我终于明白五月二十日的情况的原因了。
原来,OnTimer也是系统在定时器时间到了,向系统发送的一个消息WM_TIMER,进入消息队列,而CasyncSocket类的OnReceive事件,也是window发送的一个消息进行触发的,所以,正在处理一个消息(比如说菜单响应或OnTimer或命令按钮等)时,当然不可能去处理消息队列中的另一个消息了。看来这个底层通讯的算法,在客户端,是无法适用了,而在服务器端,因为所有的发送数据都在线程里面,所以,用这种算法,还是很不错的,对服务器适用。总算不是”一无是处”,我需要改进在客户端的底层通讯的算法了。

五月二十六日
今天把客户端的底层通讯改进了一下,添加了一个SendDataInThread函数,让它在线程里发送数据,通过向指定窗口发送消息来反馈信息。这样,需要直接发送消息,不需检验时,就可以使用SendData函数,需要检验时,就可以使用SendDataInThread函数。

五月二十七日
客户端在启动时,响应很慢,特别是有离线消息发送过来时,客户端要有2秒的时间无响应,而且,有时,服务器一个数据,发回几次。可能等待的时间(超时时间太短了),修改了一下超时时间的参数,情况好了一点。

五月二十八日
对昨日的情况,我对服务器端进行了一点修改,因为主要是在上线时,发生这种无响应的情况,我在服务器端发送数据时,每发送一次数据后,我就让该线程Sleep(K)一段时间,让客户端有足够时间去处理接受到的数据,这样,就缓解了客户端的情况,使用通讯趋于正常。

§6.2设计中遇到的问题
 由于原先的底层通讯算法不适合于客户端使用,在多次失败后,在客户端,对底层通讯算法进行了扩充。
客户端/服务器程序的调试,两个程序得一起运行,一同调试,有很多的不便的地方,特别是涉及到多线程的。
每写100行代码,平均会出现14个编译错误,当然大部分为笔误。1-2个逻辑错误。一度因为无法很快定位到逻辑错误的地方,跟踪程序花了大量的时间与精力,无法继续设计下去。
我有32x32的图象列表CimageList,我需要得到对应缩小了的16x16的图象列表,直到现在,还不知道如何实现。
我的头像是16位色的,无法使用LoadImage里的”使用透明方式”读取图象,我怎样可以得到让它去掉背景色的图象显示?
在VC中不知道如何在下拉列表框中显示图象列表,所以,我的个人资料中,没有实现头像的显示与选择
由于可能由于客户端响应慢的原因,有时,服务器向客户端发送一次以上的同一数据。是否在线程里处理会更好一些呢?
用什么函数,可能得到本机的IP地址?
消息的存储格式,有各种不同的消息,应以何种方式存储为好
如何在程序打开ODBC配置的程序?
参 考 文 献
 
官章全等 《VC60高级编程范例》 电子工业出版社 2001.1
张海藩.  《软件工程导论》清华大学出版社1998
谢希仁.  《计算机网络》 电子工业出版社. 1999.4
王国印 译.Visual C++TM 技术内幕(第二版) 清华大学出版社. 1996.5
David Bennett著  徐军 等译. Visual C++5 开发人员指南.  机械工业出版社.
木林森 等.  Visual C ++ 5.0 使用与开发.  清华大学出版社.
 汪成为 等.  面向对象分析、设计及应用.  国防工业出版社. 1992
 张海藩.  软件工程导论. 清华大学出版社. 1998.3
 谭浩强.  C程序设计.  清华大学出版社. 1994
 卢有杰 等.  C语言高级程序设计.  清华大学出版社. 1992
  汪成为 等.  面向对象分析、设计及应用.  国防工业出版社. 1992

【免费vc++网上寻呼QICQ源代码附带论文(一)】相关文章:

免费毕业论文--茶叶修剪机(一)08-11

游戏软件开发VC++05-13

网上的论文致谢(通用5篇)04-20

网上很火的论文致谢(精选13篇)04-20

网上申请学位论文答辩填写说明05-03

网上书店销售系(一)05-11

免费盘磨机传动装置(一)05-13

附带民事诉讼中的精神损害赔偿题目08-25

网上书店开题报告07-20

撰写教育论文的一般步骤11-02