【正文】
Abstract Along with the highspeed development of the puter work 《 用 VC++語言解決局域網(wǎng)聊天系統(tǒng)的 設(shè)計與 實現(xiàn) 》 第 IV 頁 共 62 頁 technology, various of applications based on work was born, like information releasing, data sharing ... The development of the LAN is the same fast. Some governments, enterprises and schools constitute a LAN first ,then join into INTERNET. So the instant messenger in LAN was borned. So I make a new design, and implement it on WINDOWS platform. In my implementation the client and the server were integrated in one program with multi thread mechanism. And had a good GUI,it was very easy to use it. And the function is very realizable. At last, it is also easy for expanding. Key words: LAN, instant messaging, client, server, multi thread, share memory, Information 《 用 VC++語言解決局域網(wǎng)聊天系統(tǒng)的 設(shè)計與 實現(xiàn) 》 第 5 頁 共 62 頁 1 引 言 課題背景及意義: 近年來,隨著全球信息化進程的不斷發(fā)展,網(wǎng)絡(luò)也在飛速發(fā)展。這些在企業(yè)內(nèi)部原有局域網(wǎng)設(shè)計之初未曾考慮到的新情況的出現(xiàn)使得局域網(wǎng)不堪重負,容易發(fā)生信息阻塞,此時,局域網(wǎng)不但不能提高生產(chǎn)效率,反而成為企業(yè)發(fā)展的瓶頸。 我在本文中將討論一種基于 Socket 的局域網(wǎng)通信工具的設(shè)計與實現(xiàn)方法。它具有信息收發(fā)速度快,保密性好,占用網(wǎng)絡(luò)帶寬資源低,占用服務(wù)器吞吐能力低,易于編程實現(xiàn)等優(yōu)點。這些軟件,在使用方面各有特色,在實現(xiàn)方面也各有所長,但基于這些產(chǎn)品正在商業(yè)運營階段,其實現(xiàn)方式屬于商業(yè)機密,具體細節(jié)不可能得知,但是它在大的方面無非就是各種利用各種平臺上的網(wǎng)絡(luò)通信接口,建構(gòu)基于下層 TCP/IP,或者UDP/IP 協(xié)議的軟件產(chǎn)品。對此,我們選擇的硬件環(huán)境和軟件環(huán)境如下: (1) 硬件環(huán)境 開發(fā)該系統(tǒng)應(yīng)盡可能采用高檔的硬件。 網(wǎng)絡(luò):局域網(wǎng)。 《 用 VC++語言解決局域網(wǎng)聊天系統(tǒng)的 設(shè)計與 實現(xiàn) 》 第 7 頁 共 62 頁 操作系統(tǒng): Windows XP 或 Window2021。 Winsockets 無疑是我們進行網(wǎng)絡(luò)編程的利器 。 ( 3)在 C/S 模式中,服務(wù)器與客戶端是相互依賴的。要求提前設(shè)想到類似的盡可能多的可能發(fā)生的事件,做出相應(yīng)的應(yīng)對措施,并向用戶提交簡單易 懂清晰明白的提示信息。并且不發(fā)生內(nèi)存泄漏之類影響系統(tǒng)運行的錯誤事件。 可行性研究: ( 1)成本可行性分析 因為本軟件只做開發(fā)學(xué)習(xí)使用,所以暫且不考慮經(jīng)濟成本及盈利問題。所謂的 Win32,其實是一個 API 規(guī)范,與 UNIX 系統(tǒng)編程接口標準 POSIX 是相對應(yīng)的。程序員必須在一個所謂的資源描述檔( .rc )中描述它們。msg, NULL, 0, 0)){ TranslateMessage(amp。} 當(dāng)消息循環(huán)捕捉到消息以后將交由窗口函數(shù) WndProc()窗口函數(shù)進行相應(yīng)的處理。MFC 構(gòu)架了一個龐大的類體系結(jié)構(gòu),在 時代就多達 189 個類,程序代碼達 252 個文件, 58 個頭文件,共 10MB 之多, 時又多加了 29 個類,但是最為主干的是下 《 用 VC++語言解決局域網(wǎng)聊天系統(tǒng)的 設(shè)計與 實現(xiàn) 》 第 11 頁 共 62 頁 面類結(jié)構(gòu)示圖所示的一些類: 圖 32 MFC 類框架主體 CObject 是 MFC 類庫的根類。 CWinThread 是所有線程類的基類,封裝了應(yīng)用程序操作的多線程功能。視圖的作用是為修改、查詢文檔等任務(wù)提供人機交互的界面。 構(gòu)建一個基于 MFC 框架的程序,可以使用 MFC 的向?qū)С绦?,但首先要明白,一個基于 MFC 的 程序可以有幾種類型:基于單文檔結(jié)構(gòu)的程序,基于多文檔結(jié)構(gòu)的程序以及基于對話框的應(yīng)用程序,不同類型的程序具有不同的程序?qū)傩?。這些協(xié)議的示例是: UDP( User Datagram Protocol)協(xié)議、 ICMP( Inter Control Message Protocol)協(xié)議、ARP(地址解析協(xié)議)和其他一些協(xié)議的協(xié)議組。數(shù)據(jù)通過這樣的分層結(jié)構(gòu)從上層傳到底層,然后通過網(wǎng)線把數(shù)據(jù)傳送出去。 IP 數(shù)據(jù)包是不可靠的,因為 IP 并沒有做任何事情來確認數(shù)據(jù)包是按順序發(fā)送的或者沒有被破壞。 UDP 的典型性應(yīng)用是如流媒體(音頻和視頻等)這樣按時到達比可 靠性更重要的應(yīng)用,或者如 DNS 查找這樣的簡單查詢 /響應(yīng)應(yīng)用,如果需要建立可靠的連結(jié),哪么所作的額外工作將是不成比例地大。一個服務(wù)程序通常在一個眾所周知的地址監(jiān)聽對服務(wù)的請求,也就是說,服務(wù)進程一直處于休眠狀態(tài),直到一個客戶向這個服務(wù)的地址提出了 連接請求。 Socket 實際在計算機 中提供了一個通信端口,可以通過這個端口與任何一個具有Socket 接口的計算機通信。 (1) : 這是 WINSOCK API 的頭文件,需要包含在項目中。進程是應(yīng)用程序的執(zhí)行實例,每個進程是由私有的虛擬地址空間、代碼、數(shù)據(jù)和其它各種系統(tǒng)資源組成,進程在運行過程中創(chuàng)建的資源隨著進程的終止而被銷毀,所使用的系統(tǒng)資源在進程終止時被釋放或關(guān)閉。 每一個進程至少有一個主執(zhí)行線程,它無需由用戶去主動創(chuàng)建,是由系統(tǒng)自動創(chuàng)建的。要說明的一點是,目前大多數(shù)的計算機都是單處理器( CPU)的,為了運行所有這些線程,操作系統(tǒng)為每個獨立線程安排一些 CPU 時間,操作系統(tǒng)以輪換方式向線程提供時間片,這就給人一種假象,好象這些線程都在同時運行。 Visual C++ 中,使用 MFC 類庫也實現(xiàn)了多線程的程序設(shè)計,使得多線程編程更加方便。 該函數(shù)在其調(diào)用進程的進程空間里創(chuàng)建一個新的線程,并返回已建線程的句柄。 該函數(shù)用于結(jié)束線程的掛起狀態(tài),執(zhí)行線程。 (5) BOOL TerminateThread(HANDLE hThread,DWORD dwExitCode)。 (6)BOOL PostThreadMessage(DWORD idThread,UINT Msg,WPARAM wParam,LPARAM lParam)。有時 ,可能有多個客戶向同一個服務(wù)器同時請求服務(wù) ,這就需要服務(wù)器決定怎樣處理這些請求。 Client/Server 模型最終可歸結(jié)為一種“請求 /應(yīng)答”關(guān)系。如下圖所示: 《 用 VC++語言解決局域網(wǎng)聊天系統(tǒng)的 設(shè)計與 實現(xiàn) 》 第 17 頁 共 62 頁 圖 41客戶機/服務(wù)器通信結(jié)構(gòu)示圖 在客戶端啟動后,客戶端計算得到本地網(wǎng)絡(luò)的廣播地址,進行廣播查找服務(wù)器端,服務(wù)器接收到客戶端的廣播信息后返回服務(wù)器地址,則客戶端接收、驗證信息并記錄服務(wù)器端地址,然后客戶端啟動定時期,定時發(fā)送信息到服務(wù)器,以告知服務(wù)器自己在線,然后服務(wù)器返回在線用戶列表,服務(wù)器依靠客戶端發(fā)送的信息來更新維護在線用戶列表。 圖 42 功能模塊圖 《 用 VC++語言解決局域網(wǎng)聊天系統(tǒng)的 設(shè)計與 實現(xiàn) 》 第 18 頁 共 62 頁 其中主線程模塊完成對網(wǎng)絡(luò)的初始化,然后啟動兩個子線程:服務(wù) 端監(jiān)聽線程以及網(wǎng)絡(luò)掃描模塊線程,然后由網(wǎng)絡(luò)掃描模塊得到當(dāng)前的網(wǎng)絡(luò)用戶分布情況,并填充相關(guān)的數(shù)據(jù)結(jié)構(gòu),然后生成用戶列表界面顯示給用戶。 數(shù)據(jù)結(jié)構(gòu)設(shè)計 ( 1)在線用戶信息結(jié)構(gòu)體: struct USERINFO { CString ip。 注:用于構(gòu)建服務(wù)器端的在線用戶單向鏈表。 服務(wù)器端: struct RECVPARAM { SOCKET sock。 //存儲在線用戶單向鏈表的頭指針 }。 CserverApp 類為應(yīng)用程序主框架類,它在后臺完成了一個基于 MFC 的應(yīng)用程序的所有基本的初始化工作,如果用戶需要在程序的初始化時加入一些自定義的操作,只需在其中的 InitInstance()函數(shù)中加入就可以了。 } 在每一個基于 MFC 的 WIN32 程 序中,它都是通過一個由全局對象啟動整個初始化過程的機制,因為根據(jù) C++的設(shè)計,一個全局對象的生成即其構(gòu)造函數(shù)的調(diào)用要先于程序的入口函數(shù)。 數(shù)據(jù)報套接字編程模型 大多數(shù)的數(shù)據(jù)報應(yīng)用程序使用固定的事件序列完成客戶端程序和服務(wù)器端程序之間的通信。數(shù)據(jù)報套接字的編程比較簡單,它不需要建立連接就可以進行網(wǎng)絡(luò)通信。在發(fā)送和接收數(shù)據(jù)之前必須建立連接。服務(wù)器端使用新建的套接字與客戶端進行通信如圖 53所示。 OnAccept:同志監(jiān)聽套接字有連接請求正在等待 ,可在時間響應(yīng)代碼中通過調(diào)用Accept()成員函數(shù)來接受客戶機的連接請求。 OnClose:通知套接字,它所連接的另外一段套接字已關(guān)閉,這樣,在連接的這端可在事件響應(yīng)代碼中調(diào)用 Close()成員函數(shù)關(guān)閉套接字。 填 充 N E T M E S S A G E結(jié) 構(gòu) 體獲 得 列 表 框 中 的 用 戶m _ b W h i s p e r i n g發(fā) 送 消 息s t r c p y ( n e t M e s s a g e . t o , _ T ( ) ) 。r e t u r n 。在這次的 課程設(shè)計 中,我應(yīng)用了VC++ 開發(fā)工具在 WINDOWS 平臺上開發(fā)了一個基于 WINDOWS 平臺的局域網(wǎng)通信工具,在這一重要的領(lǐng)域進行了相關(guān)的實踐,不管是對我的研究能力,還是實際動手能力,還 是資料查閱能力,都起了相當(dāng)大的益處。 既然設(shè)計已經(jīng)完成,課程設(shè)計 也寫到結(jié)論的地方,我希望自己能以一個良好的心態(tài)順利畢業(yè),走向社會 。 endif ///////////////////////////////////////////////////////////////////////////// // CAboutDlg dialog used for App About class CAboutDlg : public CDialog { public: CAboutDlg()。 CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { //{{AFX_DATA_INIT(CAboutDlg) //}}AFX_DATA_INIT } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX)。 //{{AFX_DATA_MAP(CServerDlg) DDX_Text(pDX, IDC_EDIT4, m_strMsg)。 ASSERT(IDM_ABOUTBOX 0xF000)。 if (!()) { pSysMenuAppendMenu(MF_SEPARATOR)。 // Set big icon SetIcon(m_hIcon, FALSE)。 thisSetWindowText(QC 服務(wù)器 )。 ()。 // Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON)。rect)。 } else { CDialog::OnPaint()。wsaData)。iMAX1。 WSACleanup()。 =0。serveraddr,sizeof(serveraddr))==SOCKET_ERROR) { MessageBox(Bind Failed)。 } if(listen(ListeningSocket,20。 closesocket(ListeningSocket)。 WSAAsyncSelect(ListeningSocket,m_hWnd,WM_SERVER_ACCEPT,FD_ACCEPT|FD_READ|FD_CLOSE)。 return false。 } ListeningSocket=socket(AF