- 相關推薦
免費vc++網上尋呼QICQ源代碼(附帶論文)(一)
第 1 章 概論
§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源代碼附帶論文(一)】相關文章:
免費vc++航空客運訂票系統+論文(一)11-22
免費網上戰友錄的設計與實現(一)03-07
免費畢業論文--茶葉修剪機(一)02-26
免費畢業論文--齒輪鏈輪套件設計(一)03-08
免費畢業論文--巧克力包裝機設計(一)03-08
免費畢業論文--管道清灰機器人設計(一)11-23
免費畢業論文--說明書(冷沖模設計(一)03-08