- 相關(guān)推薦
免費vc++網(wǎng)上尋呼QICQ源代碼(附帶論文)(一)
第 1 章 概論
§1.1 課題的來源及意義
在網(wǎng)絡(luò)無所不在的今天,在Internet上,有icq,oicq,ticq等網(wǎng)上尋呼軟件,極大程度上方便了處于在世界各地的友人之間的相互聯(lián)系,也使世界好象一下子縮小了,不管你在哪里,只要你上了網(wǎng),打開這些軟件,就可以給你的朋友發(fā)信息,不管對方是否也同時在線,只要知道他有號碼。
現(xiàn)在,企業(yè)、機關(guān)、學(xué)校都建立起了自己的局域網(wǎng),在局域網(wǎng),雖然可以通過文件共享的方式進(jìn)行通訊,但單單使用這種方式,是非常不方便的,首先,在局域網(wǎng)里的網(wǎng)上鄰居里,只能看到機器名,不清楚對方是誰,也不知道對方機器里有什么資源可以共享,而且,當(dāng)局域網(wǎng)的機器很多時,這種方式更加麻煩。于是,就想到做一個在局域網(wǎng)里的icq,在局域網(wǎng)里,我們可以通過它,實現(xiàn)在局域網(wǎng)里方便的聯(lián)絡(luò),進(jìn)行文件傳輸,消息的發(fā)布,自己共享內(nèi)容的簡介等。在學(xué)校建立起校園網(wǎng)里,這軟件可以起到方便同學(xué)之間,教師之間,師生之間的相互聯(lián)絡(luò),這樣,不用上Internet,可以節(jié)省資源,在學(xué)校這個大環(huán)境里,就可以同學(xué)之間聯(lián)系,聯(lián)絡(luò)感情,促進(jìn)同學(xué)之間的友誼,學(xué)生可以通過它來與不同寢室的同學(xué),教師討論問題。并能最大限度地利用現(xiàn)有的網(wǎng)絡(luò)資源,極大地提高工作效率。為了適應(yīng)校園網(wǎng)的建設(shè),實現(xiàn)校園網(wǎng)內(nèi)進(jìn)行消息發(fā)布,學(xué)生交流,師生交流,網(wǎng)上作業(yè)等功能。
§1.2 網(wǎng)上尋呼的軟件的現(xiàn)況
網(wǎng)上尋呼軟件在國外的有icq等,在國內(nèi)的主要有騰訊的Oicq,還有Ticq,OmO和一些在網(wǎng)頁上的即時通訊工具,像Chinaren網(wǎng)站上的WebMaster等等,都做得即美觀,且功能強大,Oicq現(xiàn)在擁有非常大的用戶群。
在局域網(wǎng)內(nèi)的網(wǎng)上尋呼,就我知道的有武漢碩思軟件公司的碩思即時通,能夠較好的完成局域網(wǎng)上尋呼,聊天,發(fā)文件,收E-mail等功能。
現(xiàn)在也有很多,在局域網(wǎng)上不使用服務(wù)器的通訊軟件,這種軟件小巧且方便,也能解決一部分問題。但是有服務(wù)器的通訊軟件,有著不可比擬的優(yōu)勢:可以發(fā)送離線消息,不管用戶當(dāng)時是否在線,下次上線時,就可以看到這條消息了。可以保存用戶的個人信息或介紹,供人查看。而且,那種通訊軟件,是以機器為通訊單元的,而這種尋呼軟件是以人為通訊單元?傊,這種軟件在局域網(wǎng)上,還是有很大的用途的,為局域網(wǎng)上通訊,帶來極大的方便。
雖然說,現(xiàn)在這個軟件已經(jīng)有公司把它開發(fā)出來了,我再做也不一定有新意,也未必可以做得更好,但作為畢業(yè)設(shè)計,也算是對我能力的一個考驗和這四個我學(xué)習(xí)知識的一個檢查。而且,我校現(xiàn)在也正在籌備建立校園網(wǎng),如果這個軟件做得比較成功的話,能為校園網(wǎng)上的通訊帶來一定的方便,我就很滿足了。
§1.3面向?qū)ο蠓椒ㄅc設(shè)計簡介
傳統(tǒng)的軟件工程方法有生命周期方法和快速原型法。
面向?qū)ο蠓椒▽W(xué)是一種全新的軟件工程方法,其出發(fā)點和基本原則是盡可能模擬人類習(xí)慣的思維方式,把構(gòu)成客觀世界的實體抽象為對象。概括地說,面向?qū)ο蠓椒▽W(xué)有四個要點:
1.認(rèn)為客觀世界是由各種對象組成的,復(fù)雜的對象可以由比較簡單的對象以某種方式組合而成;
2.把所有對象都劃分成各種對象類,每個對象類可以定義一組數(shù)據(jù)和方法;
3.按照子類和父類的關(guān)系,把若干對象類組成一個層次結(jié)構(gòu)的系統(tǒng);
4.對象彼此之間僅能通過傳遞消息互相聯(lián)系。
用面向?qū)ο蠓椒▽W(xué)開發(fā)的軟件有以下優(yōu)點:
1.與人類習(xí)慣的思維方法一致;
2.穩(wěn)定性好;
3.可重用性好;
4.可維護(hù)性好。
§1.4本章小結(jié)
隨著計算機應(yīng)用技術(shù)的日益普及,網(wǎng)絡(luò)也遍及到我們生活的每個角落,很好的利用這人資源,將為我們的工作和學(xué)習(xí),帶來極大的方便和提高工作效率,所以,開發(fā)一個局域網(wǎng)里的C/S通訊軟件,是十分必要。
由于采用面向?qū)ο蠓椒ㄩ_發(fā)軟件具有明顯的優(yōu)點,本系統(tǒng)將采用面向?qū)ο蠓椒ㄟM(jìn)行開發(fā)。由于采用面向?qū)ο蟮南到y(tǒng)模型可以使整個軟件系統(tǒng)的結(jié)構(gòu)變得更加靈活,本系統(tǒng)的結(jié)構(gòu)模型將采用面向?qū)ο蟮南到y(tǒng)模型,采用VC++6.0這個可視化開發(fā)工具進(jìn)行編碼。
第 2 章 網(wǎng)絡(luò)通訊程序的設(shè)計原理和過程
對網(wǎng)絡(luò)通訊程序的設(shè)計的原理和過程的透徹理解,是網(wǎng)絡(luò)通訊程序的前提。本章將簡要地介紹一下有關(guān)網(wǎng)絡(luò)通訊程序設(shè)計的基本知識。
§2.1 TCP/IP協(xié)議
TCP/IP是國際互聯(lián)網(wǎng)所采用進(jìn)行網(wǎng)際互連的通信協(xié)議。實際所稱的TCP/IP協(xié)議包括了在國際互聯(lián)網(wǎng)上應(yīng)用的一組協(xié)議,互聯(lián)網(wǎng)協(xié)議族是此協(xié)議族的另一個名字。這個協(xié)議族包括幾種工作在不同層次上的網(wǎng)絡(luò)協(xié)議,IP互連協(xié)議(Internet Protocol),負(fù)責(zé)主機之間的傳輸數(shù)據(jù)。TCP傳輸控制協(xié)議(Transmission Control Protocol),負(fù)責(zé)在應(yīng)用程序之間傳遞數(shù)據(jù)。UDP用戶數(shù)據(jù)報協(xié)議(User Datagram Protocol),提供給用戶進(jìn)程的無連接協(xié)議,也負(fù)責(zé)在應(yīng)用程序之間無連接傳遞數(shù)據(jù),但不執(zhí)行正確性檢查。ICMP互連網(wǎng)控制報文協(xié)議(Internet Control Message Protocol),處理主機間的差錯和傳送控制。ARP地址解析協(xié)議(Address Resolution Protocol),負(fù)責(zé)將網(wǎng)絡(luò)層地址轉(zhuǎn)換成鏈路層地址。RARP反向地址解析協(xié)議(Reverse Address Resolution Protocol),負(fù)責(zé)將鏈路層地址轉(zhuǎn)換成網(wǎng)絡(luò)層地址。
TCP/IP協(xié)議的核心是傳輸層協(xié)議(TCP、UDP)、網(wǎng)絡(luò)層協(xié)議(IP)和物理接口層,這三層通常在操作系統(tǒng)的內(nèi)核中實現(xiàn)。TCP/IP網(wǎng)絡(luò)環(huán)境下的應(yīng)用程序設(shè)計是通過網(wǎng)絡(luò)系統(tǒng)編程界面Socket實現(xiàn)的,Socket提供應(yīng)用程序與系統(tǒng)內(nèi)核之間的網(wǎng)絡(luò)編程接口。協(xié)議可以是可靠的可以是不可靠的。可靠的協(xié)議意味著當(dāng)數(shù)據(jù)通過協(xié)議傳遞時,協(xié)議保證數(shù)據(jù)正確傳輸?煽總鬏敯◣讉特征。首先,為了確保數(shù)據(jù)正確傳送,協(xié)議在通信應(yīng)用程序之間互相交換確認(rèn)信息。也就是說,程序每次發(fā)送-個報文時,都期望對方發(fā)送一個相當(dāng)于說:“我得到這個報文”的確認(rèn)信息。如果發(fā)送程序沒有收到這樣一個確認(rèn)信息,程序?qū)⒆詣又匦掳l(fā)送此報文,直到得到應(yīng)答信息為止。其次,為了確保傳輸?shù)臄?shù)據(jù)有效,可靠協(xié)議在每次傳輸時,都包含一個或更多的校驗和(CRC)。接收計算機重新計算校驗和,與收到的校驗和進(jìn)行比較。如果不匹配,就表明在傳輸過程中發(fā)生了錯誤。
傳輸控制協(xié)議TCP是一個使用校驗和、確認(rèn)信息以及其它可靠數(shù)據(jù)傳輸技術(shù)的可靠協(xié)議。相比之下,不可靠協(xié)議不能確保數(shù)據(jù)正確傳輸。協(xié)議試圖傳輸數(shù)據(jù),但不保證成功。而且,不可靠協(xié)議在傳輸失敗后,并不通知發(fā)送方應(yīng)用程序?蓪⒉豢煽繑(shù)據(jù)傳輸比作沒有返回地址的信件。如果發(fā)送地址是鍺誤的,由于郵遞系統(tǒng)不能將信退回給你,所以你就不知道信件有沒有送到。即使發(fā)送地址是正確的,也不能保證郵遞系統(tǒng)不丟失你的信件。
TCP/IP協(xié)議組中存在的兩個基本數(shù)據(jù)服務(wù)是:字節(jié)流服務(wù)和數(shù)據(jù)報服務(wù),使用字節(jié)流的協(xié)議將信息看作一串字節(jié)流進(jìn)行傳輸。協(xié)議不管要求發(fā)送或接收數(shù)據(jù)的長度和傳送數(shù)目,只是將數(shù)據(jù)看作一個簡單的字節(jié)串流。使用數(shù)據(jù)報的協(xié)議將信息視作一個獨立單元進(jìn)行傳輸。協(xié)議單獨發(fā)送每個數(shù)據(jù)報——數(shù)據(jù)報之間不相互依賴。例如,假設(shè)你使用字節(jié)流協(xié)議發(fā)送5個數(shù)據(jù)段(每個有10字節(jié))和一個包含50字節(jié)的數(shù)據(jù)段(總共100字節(jié))。連接的接收方可以按每次20字節(jié)讀數(shù)據(jù)(要讀5次)。傳輸控制協(xié)議是字節(jié)流協(xié)議。
字節(jié)流協(xié)議不關(guān)心每個數(shù)據(jù)段的長度。如果應(yīng)用程序使用字節(jié)流協(xié)議發(fā)送數(shù)據(jù),則協(xié)議能夠保證連接的另一端按照發(fā)送的順序接收數(shù)據(jù)。相比之下,傳輸?shù)酵荒康牡氐亩鄠數(shù)據(jù)報可能不會按發(fā)送順序到達(dá)。如果接收方應(yīng)用程序要求數(shù)據(jù)順序一致,應(yīng)用程序必須在數(shù)據(jù)到達(dá)后,校對這些數(shù)據(jù)。用戶數(shù)據(jù)報協(xié)議和互連網(wǎng)協(xié)議使用數(shù)據(jù)報傳輸數(shù)據(jù)。數(shù)據(jù)報類似于信件。如果你在同一天給同一個人郵寄兩封信,你無法知道那個人先收到那封信。同樣,如果連續(xù)兩天給兩個人郵信,你也不能知道哪封信先收到。收到信的順序和發(fā)送順序可能相反。
在TCP/IP術(shù)語中,端口類(Port)似于IP地址,IP地址與主機地址是相聯(lián)系的,端口和協(xié)議相聯(lián)系。IP數(shù)據(jù)報保存目的和源IP地址,同樣傳輸協(xié)議也保存源和目的端口號。如果端口這個概念對你來說很陌生,請考慮計算機上的硬件端口。你可能編寫過往硬件端口送數(shù)據(jù)的程序。例如為了打印,如果沒有其它程序的話,必須向串或并端口發(fā)送數(shù)據(jù)。PC機給它的端口命名和編號。
例如,PC機的并行打印端口稱為LPTl和LPT2,串行端口稱為COM1和COM2。在Internet上,網(wǎng)絡(luò)只是簡單地對協(xié)議端口編號。在PC機,LPT1表示并行端口1。成千個PC機應(yīng)用程序使用此方案。多年來,程序員編寫PC程序時都假定LPT1表示并行打印端口1。同樣,程序員將每個Internet協(xié)議端口與一個特定的應(yīng)用程序和功能聯(lián)系在一起。
Internet包括像FTP、Telnet和Mail這樣廣泛使用的應(yīng)用程序采用的應(yīng)用協(xié)議,在Internet上,這些應(yīng)用程序使用一種叫做“通用口分配”的端口。通用口分配是特定應(yīng)用程序廣泛使用的一個協(xié)議端口。像PC程序員使用打印端口LPT1用于打印,Internet程序員也對具體應(yīng)用程序使用許多協(xié)議端口。例如,平凡文件傳輸協(xié)議(FTP)的通用口分配是端口號21的。Telnet的通用口分配是端口號23。
§2.2 客戶/服務(wù)器程序的設(shè)計
客戶機/服務(wù)器模型也是一種網(wǎng)絡(luò)模型,但與前述的模型不同,它并不是定義了網(wǎng)絡(luò)的層次結(jié)構(gòu),而是描述了一種網(wǎng)絡(luò)程序運行的方式。
客戶及/服務(wù)器模型將網(wǎng)絡(luò)應(yīng)用程序分為客戶和服務(wù)器兩部分?蛻舴綄Ψ⻊(wù)器方發(fā)送信息請求,服務(wù)器方對其做出相應(yīng)回答,提供服務(wù)。在TCP/IP網(wǎng)絡(luò)應(yīng)用中,多數(shù)網(wǎng)絡(luò)應(yīng)用程序是使用客戶/服務(wù)器模型設(shè)計的。服務(wù)程序通常在一個眾所周知的地址監(jiān)聽對服務(wù)的請求,也就是說,服務(wù)進(jìn)程一直處于休眠狀態(tài),直到一個客戶程序提出了請求信息。此時,服務(wù)程序被"驚醒"并且為客戶提供服務(wù),對客戶的請求作出適當(dāng)?shù)姆磻?yīng)。雖然基于連接的服務(wù)是設(shè)計客戶/服務(wù)器應(yīng)用程序的標(biāo)準(zhǔn),但有些服務(wù)也是可以通過數(shù)據(jù)報Socket提供的。
通常,網(wǎng)絡(luò)應(yīng)用程序包含兩個獨立的應(yīng)用程序:客戶程序和服務(wù)器程序。但是,也可以設(shè)計同時完成這兩種功能的程序,例如,一些服務(wù)器程序如果不能完成一個服務(wù)請求時,它將轉(zhuǎn)而充當(dāng)客戶程序,向其它服務(wù)器程序請求信息。這方面的一個典型例子就是提供Internet從域名到IP地址映射服務(wù)的DNS服務(wù)器。
為了充分理解TCP/IP協(xié)議族,必須理解幾個重要術(shù)語。這些術(shù)語指出了兩個TCP/IP傳輸協(xié)議:用戶數(shù)據(jù)包協(xié)議(UDP)和傳榆控制協(xié)議(TCP)之間的區(qū)別。這些術(shù)語進(jìn)一步描述了與網(wǎng)絡(luò)連接、協(xié)議可靠性以及數(shù)據(jù)服務(wù)有關(guān)的協(xié)議特性。
當(dāng)建立服務(wù)器程序時,應(yīng)該將服務(wù)器程序設(shè)計成等候客戶的請求。你知道,TCP傳輸層通過協(xié)議端口和應(yīng)用程序 (像服務(wù)器和客戶)通信,也就是說,為了按收客戶請求,服務(wù)器程序必須對傳輸層的一個特定協(xié)議端口進(jìn)行偵聽。當(dāng)服務(wù)器配置socket接口時,它使用bind()函數(shù)讓socket執(zhí)行體登記一個協(xié)議端口。也就是說,程序告訴socket執(zhí)行體使用哪-個協(xié)議端口進(jìn)行數(shù)據(jù)傳送。Socket執(zhí)行體接著告訴傳輸層某個特定協(xié)議端口已被使用,并將其收到的所有數(shù)據(jù)傳送給Socket API。
使用無連接協(xié)議的程序和使用面向連接協(xié)議的服務(wù)器程序之間的主要相似之處是它們都必須對一個協(xié)議端口進(jìn)行偵聽。例如,無連接和連接服務(wù)器程序必須在協(xié)議端口偵聽客戶請求。同樣,由于無連接客戶程序沒有和遠(yuǎn)地主機建立直接連接,所以它也必須對協(xié)議端口進(jìn)行偵聽,以便接收以對它服務(wù)請求產(chǎn)生的數(shù)據(jù)報應(yīng)答。Socket API中的bind()函數(shù)讓程序?qū)⒁粋本地地址(包括主機地址和協(xié)議端口)和一個Socket聯(lián)系起來。
下面程序行顯示了一個典型的函數(shù)調(diào)用:
result=bind ( socket_handle, local_structure, socket_address, address_ length)
無連接客戶程序也對一個協(xié)議端口進(jìn)行偵聽。使用無連接協(xié)議的程序不和遠(yuǎn)地主機建立直接連接。無連接客戶程序使用數(shù)據(jù)報發(fā)送網(wǎng)絡(luò)服務(wù)請求,它不建立點到點連接。因此無連接客戶程序必須在一個協(xié)議端口,對應(yīng)答數(shù)據(jù)報進(jìn)行偵聽。與服務(wù)器程序一樣,無連接客戶程序也使用bind函數(shù)讓Socket執(zhí)行體登記協(xié)議端口。也就是說,類似服務(wù)器程序,無連接客戶程序告訴Socket執(zhí)行體使用哪個協(xié)議端口進(jìn)行數(shù)據(jù)傳輸。Socket執(zhí)行體處理傳輸層內(nèi)UDP軟件模塊和客戶程序之間的接口。
第 3 章 軟件功能與界面需求
提供基于TCP/IP網(wǎng)絡(luò)的即時消息傳送、消息廣播、實時聊天、文件傳輸?shù)裙δ堋?具體列舉如下:
支持多賬號
可以同時發(fā)送同一個消息給多人,通過輸入這些人的號碼列表或姓名列表
可以同時發(fā)送一個消息給所有好友
有權(quán)限的人可以向所有用戶發(fā)送“消息廣播”,便于消息的發(fā)布
即使用戶不在線,也能通過服務(wù)器發(fā)送離線消息
提供消息、聊天的歷史記錄,方便對信息的查看和管理
提供查看在線的人的功能
提供按ID或姓名查找用戶的功能,添加用戶方便
小窗口顯示,不占用屏幕很大的空間,
支持熱鍵調(diào)出后臺的應(yīng)用程序。
應(yīng)用程序運行后,在任務(wù)欄右邊生成一個圖標(biāo),單擊彈出在線狀態(tài) 菜單,雙擊顯示應(yīng)用程序窗口,右擊彈出主菜單。
支持隱身登陸,可以看到在線的朋友,朋友卻不知道你上線了
可以實時顯示用戶的狀態(tài)和隨時改變自己的狀態(tài)
提供了自動彈出消息
好友上線通知
好友下線更新
有權(quán)限的人可以發(fā)系統(tǒng)廣播(或在服務(wù)器上發(fā))
查看好友信息
按姓名或號碼查找某人
在好友列表中刪除某人
可以選擇在某人的好友中刪除自己
更改個人信息
系統(tǒng)設(shè)置
給在線好友傳文件
消息管理器
在程序中設(shè)定最大,最小窗口尺寸(寬度,高度)
主窗口總是浮在最上端
速度快,占用資源少
第 4 章 概要設(shè)計和詳細(xì)設(shè)計
本章將論述軟件系統(tǒng)的面向?qū)ο笤O(shè)計過程。用Visual C++語言在Windows環(huán)境下編程實現(xiàn)。
§4.1總體設(shè)計概述
采用客戶端——服務(wù)器模型,使用從MFC類中的CAsyncSocket類的派生類進(jìn)行實現(xiàn)底層通訊,底層利用UDP數(shù)據(jù)報協(xié)議進(jìn)行通訊,這樣,便于客戶端之間的直接通訊,也可以高效的傳送消息。因為使用UDP協(xié)議進(jìn)行通訊,所以要自己控制其可靠性。我每發(fā)送一個數(shù)據(jù),接受方接受到數(shù)據(jù)后,會發(fā)回一個響應(yīng)信息,發(fā)送方在一個超時時間內(nèi),收到響應(yīng)信息,就表示發(fā)送數(shù)據(jù)成功,若沒有收到,就表示發(fā)送失敗,會按用戶指定的次數(shù)N,重試N次,如果N次都失敗,就返回發(fā)送數(shù)據(jù)失敗。當(dāng)然,發(fā)回來的確認(rèn)信息也可能丟失,但確認(rèn)信息很短,相對來說,丟失的機率會小一些,是一個折中的辦法。
為了保存用戶信息和好友信息及一些相關(guān)數(shù)據(jù),服務(wù)器使用到數(shù)據(jù)庫技術(shù)。服務(wù)器的數(shù)據(jù)庫采用的是ODBC的ACCESS數(shù)據(jù)源,服務(wù)器訪問數(shù)據(jù)庫,用的是MFC中的CDatabase和CRecordset,因為,對數(shù)據(jù)庫的操作簡單,服務(wù)器端,我只要功能,不需做界面,所以使用Sql語句直接訪問數(shù)據(jù)庫,已經(jīng)足夠滿足要求了。
服務(wù)器運行的流程為:
服務(wù)器運行后,開啟服務(wù),則服務(wù)器開始偵聽用戶請求,如有信息發(fā)送過來,首先,發(fā)送回確認(rèn)信息,然后,建立一個線程,處理接受到的數(shù)據(jù)。在線程里,按照接受到數(shù)據(jù)的類別,進(jìn)行相應(yīng)的處理,如有需要,會向用戶發(fā)送處理的結(jié)果,或成功或失敗的消息,處理結(jié)束后,線程就結(jié)束了。這樣,可以實時接受每個用戶的請求,不會因為處理一個用戶的請求,而忽略了其它用戶。
服務(wù)器端主要是為用戶存儲必要的信息,協(xié)調(diào)用戶之間的通訊,服務(wù)器端的設(shè)計,主要在功能上面。服務(wù)器端的設(shè)計和底層通訊的方法,將是我講述的重點。
客戶端的運行流程為:
若有本地用戶信息,則取出本地用戶信息,顯示登陸窗口,若沒有,則顯示用戶注冊窗口(在登陸窗口里,也可以選擇用戶注冊)。登陸時,可選擇是否隱身,進(jìn)入系統(tǒng)后,好友列表中,在線的人,將以高亮度顯示,并處在列表的上頭。不在線的人,將以灰色顯示。登陸后,如果有的話,服務(wù)器會發(fā)來好友給你發(fā)送的離線消息或廣播消息。如果有好友上線了,就會通知你,好友下線了,你也可以在好友列表中看到,你可能接受到別人給你發(fā)送的消息,或廣播消息等。根據(jù)用戶的操作,可以向好友發(fā)送消息,查看好友信息,查看在線的人,查找用戶,發(fā)送廣播消息等等功能。
客戶端主要是提供給用戶一個友好的用戶界面,方便用戶操作,客戶端主要負(fù)責(zé)從服務(wù)器上得到數(shù)據(jù)后,顯示給用戶。從服務(wù)器得到好友的IP和Port后,就可以直接與好友進(jìn)行通訊,聊天等等?蛻舳酥饕墙缑娴脑O(shè)計(除了底層通訊的以外),根據(jù)不同的要求,向服務(wù)器發(fā)送各種類型的請求。然后等待服務(wù)器的響應(yīng)?蛻舳说慕缑娴脑O(shè)計很繁瑣,沒有詳細(xì)介紹的必要,所以,我的重點,將放在服務(wù)器的設(shè)計上?蛻舳酥皇呛喴恼f明一下。
§4.2服務(wù)器數(shù)據(jù)庫的設(shè)計:
服務(wù)器數(shù)據(jù)庫設(shè)計的要求是要能夠滿足客戶端的需求,保存用戶信息和用戶好友信息,提供離線消息的服務(wù),和發(fā)廣播消息的服務(wù)等。總共有五個表:
用戶信息表(Users)好友信息表(Friends)廣播消息表(Broadcast)離線廣播表(OffBroadcast)離線消息表(OffMsg)
用戶信息表(Users)
主鍵: UserId
UserId 自動編號 4字節(jié)長整形
Id 用戶帳號 4字節(jié)長整形
Photoid 用戶的圖象編號 4字節(jié)長整形
password 用戶登陸的密碼 字符串
name 用戶的姓名 字符串
sex 用戶的性別 單字節(jié)整形 0 男 1 女 2 未知
age 用戶的年齡 字符串 (為了適應(yīng)不愿填寫此項的人)
canbeadd 能否被人加為好友
//單字節(jié)整形 (0,1,2 不能被加入,允許被任何人加入,需要身份驗證)
email 電子信箱 字符串
homepage 個人主頁 字符串
address 地址 字符串
phone 電話 字符串
fax 傳真 字符串
department 部門 字符串
description 個人簡介 字符串
好友信息表(Friends)
主鍵:Num
Num 自動編號 4字節(jié)長整形
MyId 自己帳號 4字節(jié)長整形
FriendId 朋友帳號 4字節(jié)長整形
廣播消息表(Broadcast)
保存發(fā)送的廣播消息
主鍵:MsgId
MsgId 自動編號 4字節(jié)長整形
SendTime 發(fā)送時間 4字節(jié)長整形
SenderId 發(fā)送者的帳號 4字節(jié)長整形
Msg 發(fā)送的消息 備注類型
離線廣播表(OffBroadcast)
保存那些還沒有發(fā)送廣播消息的用戶
主鍵:Num
Num 自動編號 4字節(jié)長整形
RecvId 接受者的帳號 4字節(jié)長整形
MsgId 廣播消息號 4字節(jié)長整形 (對應(yīng)廣播消息表的MsgId)
離線消息表(OffMsg)
保存用戶之間發(fā)送的離線消息
MsgId 自動編號 4字節(jié)長整形
RecvId 接受者的帳號 4字節(jié)長整形
SenderId 發(fā)送者的帳號 4字節(jié)長整形
RecvTime 接受的時間 4字節(jié)長整形
nIndex 發(fā)送消息的類型 4字節(jié)長整形
Msg 發(fā)送的消息 備注類型
§4.3類設(shè)計的總體結(jié)構(gòu)
服務(wù)器的類總體結(jié)構(gòu):
一.主應(yīng)用程序類
CServerApp
包含全局的數(shù)據(jù)結(jié)構(gòu)
二.傳送信息類
CData,CMsg1,CMsg2,CMsg3,CMsg4,CMsgChangePI,CMsgModifyPwd, CMsgOnlineFriend,CMsgPerson,CshowOnlinePeople
處理傳輸數(shù)據(jù)
三.SOCKET通訊類
CServerSocket, CSendSocket, CRecvSocket
處理底層通訊的類,與外部的接口是CserverSocket類,提供了一個簡單的接口
四.其它類
CMainFrame,CServerDoc,CServerView,CSetupDlg,CAboutDlg
UserInfo結(jié)構(gòu)存儲在線人的信息
客戶端的類總體結(jié)構(gòu):
一、應(yīng)用程序類
CClientApp
包含全局的數(shù)據(jù)結(jié)構(gòu)
二、傳送信息類
CData,CMsg1,CMsg2,CMsg3,CMsg4,CMsgChangePI,CMsgModifyPwd, CMsgOnlineFriend,CMsgPerson,CshowOnlinePeople
處理傳輸數(shù)據(jù)
三.SOCKET通訊類
CClientSocket
處理底層通訊的類,提供了一個簡單的接口
四.用程序框架類
CmainFrame
處理用戶界面和一些接受數(shù)據(jù)的響應(yīng),主要的處理過程都在這個類里實現(xiàn)。
五.對話框類
CfriendDetailDlg 顯示用戶詳細(xì)信息的對話框類
CloginDlg 顯示登陸窗口的對話框類
ClookDlg 顯示查看消息的對話框類
CregisterDlg 顯示注冊窗口的對話框類
CsetupServerDlg 修改服務(wù)器設(shè)置的對話框
CtalkDlg 顯示發(fā)送消息對話框的類
CshowBroadcastDlg 顯示廣播消息的對話框
CshowAddMsgDlg 顯示被加為好友的信息的對話框
CmultiSendDlg 通過姓名或ID列表的向多人發(fā)送信息的對話框
CsendBroadcastDlg 發(fā)送廣播消息的對話框
CsendToAllDlg 向所有好友發(fā)送消息的對話框
CModifyPIDlg 修改個人信息的對話框
六.界面類
CGfxGroupEdit,CGfxOutBarCtrl,CGfxPopupMenu
實現(xiàn)像OutBar和oicq樣式的那種滾動分欄的界面類,從Internet,上獲得的源代碼,通過修改一些接口,使之更適合我的應(yīng)用。提供了一個漂亮的界面。
TrayIcon類
處理在任務(wù)欄上添加.修改.刪除圖標(biāo)的類。封閉了Window的API函數(shù)
八.全局結(jié)構(gòu):
UserInfo結(jié)構(gòu)存儲在線人的信息
FriendState 在好友線信息結(jié)構(gòu)
SaveMsg 消息的存儲結(jié)構(gòu)
Sparam 傳給線程的參數(shù)結(jié)構(gòu)
§4.4服務(wù)器端的常量定義
在這里,定義和申明了一些全局函數(shù),常量,宏和全局?jǐn)?shù)據(jù)結(jié)構(gòu),包括用戶配置文件名,默認(rèn)的參數(shù)等,總之,修改程序中的參數(shù)簡單,直接修改頭文件就可以了,因為所使用的數(shù)值性的參數(shù),都在這里定義了。
#define ResponseMsg "ok" 發(fā)送數(shù)據(jù)時,發(fā)回的響應(yīng)消息標(biāo)志
#define SETUPFILE "config.ini" 服務(wù)器的保存配置文件
#define DEFAULT_SEND_NUM 5 默認(rèn)的發(fā)送端口的數(shù)量
#define DEFAULT_DATAS_PWD "" 默認(rèn)的數(shù)據(jù)源的訪問密碼
#define DEFAULT_DSN "IDServer" 默認(rèn)的數(shù)據(jù)源名稱
#define DEFAULT_UID "" 默認(rèn)的數(shù)據(jù)源的訪問的UID
#define DEFAULT_BROADCAST_PWD "1234567890" 默認(rèn)的發(fā)送廣播密碼
#define DEFAULT_RECV_PORT_STR "4000,4001,4002"
默認(rèn)的服務(wù)器接受端口號列表
const int ListenSocketNum=10; 最大的接受端口的個數(shù)
const int SendSocketNum=15; 最大的發(fā)送端口個數(shù)
const int TimeWaitForRes=1000; 等待響應(yīng)的超時時間
const int MaxUserNumber=500; 服務(wù)器端最大的用戶數(shù)
const int UserIdRadix=2000; 用戶帳號開始的基數(shù)(從這個基數(shù)開始增加)
const int PersonNumEveryTime=20; 請求查看在線的人時,每次最多發(fā)回的人數(shù)
const int TimerSpanServer=30000; 服務(wù)器的一個運行時間間隔,過一個這個時間間隔,服務(wù)器就檢查一次,看用戶是否仍然在線
const int DataBufLength=500; 發(fā)送數(shù)據(jù)的最大長度
const int MaxResponseMsgLength=20; 最大的響應(yīng)消息長度
const int CheckBufLength=512; 檢查發(fā)回響應(yīng)的一個緩沖區(qū)長度
保存在線人的信息的數(shù)據(jù)結(jié)構(gòu)
typedef struct{
BYTE State; //0 不在線,1 在線,2 隱身
BYTE CanbeAdd;
DWORD Id;
DWORD IP;
DWORD Port;
DWORD PhotoId;
CString Name;
CString Department;
}UserOnline;
全局函數(shù)
UINT ProcessRecvData(LPVOID param);
處理用戶請求的線程服務(wù)函數(shù)
UINT CheckOnline(LPVOID param);
處理定時檢查用戶是否仍然在線的線程函數(shù)
服務(wù)器接受到的消息類型
#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響應(yīng)加為好友請求反饋信息
#define REFUSE_AS_FRIEND 9 //CMsg1 響應(yīng)加為好友請求反饋信息
#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
客戶端接受來自服務(wù)器發(fā)送的數(shù)據(jù)
#define RE_ADD_AS_FRIEND 31
//CMsg3 index,myid,value(0,1,2,3)(別人拒絕,成功加入,要求驗證人份,此人已經(jīng)為好友)
#define RE_TEST_BROADCAST_PWD 32
//CMsg3 index,myid,value (0,1) 密碼錯誤,密碼正確
#define TOTAL_ONLINE 33
//CMsg3 index,myId,Value 響應(yīng)發(fā)送的總在線人數(shù)信息
#define RE_LOGIN_INFO 34
//CMsg3 index,myid,value (0,1,2) 帳號不存在,密碼錯誤,OK
#define RECV_SHOW_ONLINE 35 CshowOnlinePeople 回復(fù)查看在線的人
#define FOUND_FRIEND_BY_NAME 36 CshowOnlinePeople按姓名查找返回結(jié)果
#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按號碼查找,返回查找結(jié)果
#define RE_FRIEND_DETAIL 44 //CMsgPerson 回復(fù)查詢好友信息的請求
#define ALL_FRIEND_ID 45 //CMsg2 收到這個信息,這表示登陸成功
#define ONLINE_FRIEND 46 //CMsgOnlineFriend
#define BE_ADDED_AS_FRIEND 47 //CMsg1 響應(yīng)好友加入的消息
#define SYSTEM_BROADCAST 48 //CMsg1 發(fā)送系統(tǒng)廣播
§4.5客戶端的常量定義
在這里,定義和申明了一些全局函數(shù),常量,宏和全局?jǐn)?shù)據(jù)結(jié)構(gòu),包括用戶配置文件名等,總之,修改程序中的參數(shù)簡單,直接修改頭文件就可以了,因為所使用的數(shù)值性和可變性的參數(shù),都在這里定義了。
#define WM_RECIEVE_MSG WM_USER+104
//客戶端接受到數(shù)據(jù)后向父窗口發(fā)送的消息
#define WM_SENDINTHREAD_RES WM_USER+105
//調(diào)用在工作線程中發(fā)送數(shù)據(jù)時,發(fā)送后向窗口發(fā)送的反饋消息
#define WM_SHOW_FRIEND_DETAIL WM_USER+106
//發(fā)給CfriendDetailDlg對話框的一個消息,讓它顯示指定人的詳細(xì)資料,傳入的參數(shù)中WPARAM 是需要顯示的人的UserInfo數(shù)據(jù)的指針,LPARAM是FriendState數(shù)據(jù)的指針.
#define WM_RECVMSG WM_USER+ 107
//發(fā)給ClookDlg對象框的一個消息,讓它顯示別人發(fā)來的信息窗口,一有數(shù)據(jù)傳到,就向它發(fā)送這個消息即可,就會顯示一個查看消息的對話框,接口簡單。傳入的參數(shù)中WPARAM 是需要顯示的人的UserInfo數(shù)據(jù)的指針,LPARAM是FriendState數(shù)據(jù)的指針.
#define WM_SEND_MSG WM_USER+108
//發(fā)給CtalkDlg對象框的一個消息,指示我要對指定對象發(fā)送消息,只要向其對象框?qū)ο蟀l(fā)送這個消息,就會打開一個發(fā)送消息的對話框,不需知道內(nèi)部細(xì)節(jié)。傳入的參數(shù)中WPARAM 是需要顯示的人的UserInfo數(shù)據(jù)的指針,LPARAM是FriendState數(shù)據(jù)的指針.
#define ResponseMsg "ok" //確認(rèn)信息串
#define USERFILE "users.db" //保存用戶的好友信息的文件
#define MSGFILE "msg.db" //保存用戶聊天記錄的文件
#define ALLUSERIDFILE "client.cfg"
//客戶端的一個記錄所有登陸帳號的文件
#define USERSETUP "config.dat" //客戶端的一個配置文件
#define FACEINIFILE "face\\face.ini" //頭像文件的記錄文件
在這里略去與服務(wù)器相同的:
const int TimeWaitForRes=3000; 發(fā)送數(shù)據(jù)超時時間
const int PersonNumEveryTime=20;查看在線的人,每次發(fā)回的多少人
const int TimerSpanClient=40000; 客戶端每隔這個時間,若沒有收到TOTAL_ONLINE消息(所有在線人數(shù)),就判斷客戶端已經(jīng)掉線了。
const int DataBufLength=1000; 發(fā)送接受數(shù)據(jù)最大長度
const int MaxResponseMsgLength=20;
const int UserFileReservedLength=20;
//用戶user.db文件中,前面保留的字節(jié)數(shù),以備以后擴(kuò)充使用
const int MaxPasswordLength=16;密碼的最長長度
const int LimitMaxMsgLength=900;限制每次發(fā)送消息的字節(jié)數(shù)
const int AutoSaveTime=200000; 自動保存用戶信息的間隔時間
const int CheckBufLength=128; 檢查確認(rèn)信息的緩沖區(qū)長度
必要的類申明,否則以下幾個數(shù)據(jù)結(jié)構(gòu)會有編譯錯誤
class CData;
class CMsg1;
class CMsg2;
class CLookDlg;
class CTalkDlg;
class CFriendDetailDlg;
class CClientSocket;
在客戶端保存用戶詳細(xì)信息的數(shù)據(jù)結(jié)構(gòu)
struct UserInfo{
BYTE HaveDetail; //(0 沒有詳細(xì)資料, 1 有)
BYTE CanbeAdd;
//能否被加入的標(biāo)志(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(); //對各個成員進(jìn)行初始化
};
//保存消息的數(shù)據(jù)結(jié)構(gòu)
struct SaveMsg
{
DWORD ID;
CTime Time;
CString Msg;
};
保存好友的在線、收發(fā)的消息、在線的IP和Port以及發(fā)送消息、查看消息、好友詳細(xì)信息的窗口的指針等一些相關(guān)信息的數(shù)據(jù)結(jié)構(gòu),這些都是運行時的數(shù)據(jù)結(jié)構(gòu),不需要存儲的數(shù)據(jù)。對話框都是無框式對話框,所有,必須保存各個對話框的指針。
struct FriendState
{
FriendState();//做必要的初始化操作
~FriendState();//刪除動態(tài)產(chǎn)生的數(shù)據(jù)
BYTE OnlineState; //(0,1,2 離線,在線,隱身)
DWORD IP; 在線的IP
DWORD Port; 在線的Port
CArray<SaveMsg*,SaveMsg*>aMsg; 收發(fā)的消息列表
int nCu這個算法即麻煩,又易出錯,真不知當(dāng)時是怎么想的。
現(xiàn)在的算法是:
設(shè)一個緩沖區(qū)長度為N,然后,為每一次數(shù)據(jù)進(jìn)行統(tǒng)計,發(fā)一次,就加1,然后把發(fā)送數(shù)據(jù)中的This=count%N,且把緩沖區(qū)中第This個成員設(shè)為0,在發(fā)送端,就要數(shù)組中的第This個成員是否為1即可,在接受到的確認(rèn)信息中,取出This項,再為緩沖區(qū)中第This項設(shè)為1,這樣就可以快速且可靠的判斷發(fā)送數(shù)據(jù)是否得到響應(yīng)回來了。
五月二十日
今天發(fā)生了一個怪事,我在調(diào)試程序時,發(fā)現(xiàn)在,不能在服務(wù)器的消息處理消息和OnTimer里面寫發(fā)送數(shù)據(jù)的代碼,否則,怎么都發(fā)送不成功,
好像它是非得此消息處理函數(shù)或OnTimer執(zhí)行完畢,才讓其它線程運行,我的發(fā)送函數(shù),總是得不到正確結(jié)果,我一度懷疑我的底層通訊算法的合理性。后來,我也不知道如何解決,感覺是一個無法逾越的問題,非常失落…………………………………………
晚上,當(dāng)我重新拿起來的時候,試了試,又覺得這不是不可逾越的問題,只要回避那種情況,就可以了。
我把在OnTimer里處理的事情放在一個線程里去做,完成同樣的功能,現(xiàn)在,檢查人是否仍然在線的函數(shù),現(xiàn)在終于又成功了。真是太高興了。
可是,我可能沒有足夠的時間來完成這個程序了。真可惜。我必須開始寫論文了,否則,我將無法完成任務(wù)。
五月二十一日
今天,查到用LoadImage()函數(shù),可以讀取存在磁盤上的圖象文件,客戶端顯示的頭像的問題,終于可以解決了。可是又遇到了問題,我有32x32的16位色的圖象,顯示時,不知道如何使其透明背景色,因為圖象有背景色,所以顯示時,看上去無法與背景一樣的顏色,而且,我不知道如何由32x32的圖象列表,得到相應(yīng)的16x16的圖象列表,因為我需要以小圖標(biāo)的樣式顯示。我該如何做呢?有人幫我就好了。
五月二十二日
在客戶端,我的界面用的是在網(wǎng)上找到的一個源代碼
CGfxOutBarCtrl類,可以實現(xiàn)象OutLook和Oicq的那種滾動的分欄條,今天終于看懂了接口部分代碼,可以隨意更改為我用了。
五月二十四日
今天,我終于明白五月二十日的情況的原因了。
原來,OnTimer也是系統(tǒng)在定時器時間到了,向系統(tǒng)發(fā)送的一個消息WM_TIMER,進(jìn)入消息隊列,而CasyncSocket類的OnReceive事件,也是window發(fā)送的一個消息進(jìn)行觸發(fā)的,所以,正在處理一個消息(比如說菜單響應(yīng)或OnTimer或命令按鈕等)時,當(dāng)然不可能去處理消息隊列中的另一個消息了。看來這個底層通訊的算法,在客戶端,是無法適用了,而在服務(wù)器端,因為所有的發(fā)送數(shù)據(jù)都在線程里面,所以,用這種算法,還是很不錯的,對服務(wù)器適用?偹悴皇恰币粺o是處”,我需要改進(jìn)在客戶端的底層通訊的算法了。
五月二十六日
今天把客戶端的底層通訊改進(jìn)了一下,添加了一個SendDataInThread函數(shù),讓它在線程里發(fā)送數(shù)據(jù),通過向指定窗口發(fā)送消息來反饋信息。這樣,需要直接發(fā)送消息,不需檢驗時,就可以使用SendData函數(shù),需要檢驗時,就可以使用SendDataInThread函數(shù)。
五月二十七日
客戶端在啟動時,響應(yīng)很慢,特別是有離線消息發(fā)送過來時,客戶端要有2秒的時間無響應(yīng),而且,有時,服務(wù)器一個數(shù)據(jù),發(fā)回幾次。可能等待的時間(超時時間太短了),修改了一下超時時間的參數(shù),情況好了一點。
五月二十八日
對昨日的情況,我對服務(wù)器端進(jìn)行了一點修改,因為主要是在上線時,發(fā)生這種無響應(yīng)的情況,我在服務(wù)器端發(fā)送數(shù)據(jù)時,每發(fā)送一次數(shù)據(jù)后,我就讓該線程Sleep(K)一段時間,讓客戶端有足夠時間去處理接受到的數(shù)據(jù),這樣,就緩解了客戶端的情況,使用通訊趨于正常。
§6.2設(shè)計中遇到的問題
由于原先的底層通訊算法不適合于客戶端使用,在多次失敗后,在客戶端,對底層通訊算法進(jìn)行了擴(kuò)充。
客戶端/服務(wù)器程序的調(diào)試,兩個程序得一起運行,一同調(diào)試,有很多的不便的地方,特別是涉及到多線程的。
每寫100行代碼,平均會出現(xiàn)14個編譯錯誤,當(dāng)然大部分為筆誤。1-2個邏輯錯誤。一度因為無法很快定位到邏輯錯誤的地方,跟蹤程序花了大量的時間與精力,無法繼續(xù)設(shè)計下去。
我有32x32的圖象列表CimageList,我需要得到對應(yīng)縮小了的16x16的圖象列表,直到現(xiàn)在,還不知道如何實現(xiàn)。
我的頭像是16位色的,無法使用LoadImage里的”使用透明方式”讀取圖象,我怎樣可以得到讓它去掉背景色的圖象顯示?
在VC中不知道如何在下拉列表框中顯示圖象列表,所以,我的個人資料中,沒有實現(xiàn)頭像的顯示與選擇
由于可能由于客戶端響應(yīng)慢的原因,有時,服務(wù)器向客戶端發(fā)送一次以上的同一數(shù)據(jù)。是否在線程里處理會更好一些呢?
用什么函數(shù),可能得到本機的IP地址?
消息的存儲格式,有各種不同的消息,應(yīng)以何種方式存儲為好
如何在程序打開ODBC配置的程序?
參 考 文 獻(xiàn)
官章全等 《VC60高級編程范例》 電子工業(yè)出版社 2001.1
張海藩. 《軟件工程導(dǎo)論》清華大學(xué)出版社1998
謝希仁. 《計算機網(wǎng)絡(luò)》 電子工業(yè)出版社. 1999.4
王國印 譯.Visual C++TM 技術(shù)內(nèi)幕(第二版) 清華大學(xué)出版社. 1996.5
David Bennett著 徐軍 等譯. Visual C++5 開發(fā)人員指南. 機械工業(yè)出版社.
木林森 等. Visual C ++ 5.0 使用與開發(fā). 清華大學(xué)出版社.
汪成為 等. 面向?qū)ο蠓治、設(shè)計及應(yīng)用. 國防工業(yè)出版社. 1992
張海藩. 軟件工程導(dǎo)論. 清華大學(xué)出版社. 1998.3
譚浩強. C程序設(shè)計. 清華大學(xué)出版社. 1994
盧有杰 等. C語言高級程序設(shè)計. 清華大學(xué)出版社. 1992
汪成為 等. 面向?qū)ο蠓治、設(shè)計及應(yīng)用. 國防工業(yè)出版社. 1992
【免費vc++網(wǎng)上尋呼QICQ源代碼附帶論文(一)】相關(guān)文章:
免費畢業(yè)論文--茶葉修剪機(一)08-11
游戲軟件開發(fā)VC++05-13
網(wǎng)上的論文致謝(通用5篇)04-20
網(wǎng)上申請學(xué)位論文答辯填寫說明05-03
網(wǎng)上書店銷售系(一)05-11
免費盤磨機傳動裝置(一)05-13
附帶民事訴訟中的精神損害賠償題目08-25
網(wǎng)上書店開題報告07-20
撰寫教育論文的一般步驟11-02