版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
基于TCP協(xié)議的網(wǎng)絡(luò)通信系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)摘要:網(wǎng)絡(luò)通信,由于其具有實(shí)時(shí)性、跨平臺(tái)性、本錢低、效率高等優(yōu)點(diǎn)而受到廣泛的使用。設(shè)計(jì)并實(shí)現(xiàn)一個(gè)能夠處理多用戶進(jìn)行實(shí)時(shí)、平安的即時(shí)通信系統(tǒng)具有較強(qiáng)的現(xiàn)實(shí)意義。即時(shí)通信的底層通信是通過SOCKET套接字接口實(shí)現(xiàn)的。當(dāng)前的主流UNIX系統(tǒng)和微軟的WINDOWS系統(tǒng)都在內(nèi)核提供了對(duì)SOCKET字接口的支持。使用這個(gè)統(tǒng)一的接口,可以編寫一個(gè)可移植的TCP/IP通信程序。使信息能夠在INTERNET上可靠的傳輸。本文設(shè)計(jì)并實(shí)現(xiàn)了基于局域網(wǎng)內(nèi)的簡(jiǎn)單即時(shí)通信系統(tǒng),系統(tǒng)采用C/S模式,底層通信通過SOCKET套接字接口實(shí)現(xiàn),效勞器負(fù)責(zé)客戶端的登錄驗(yàn)證,好友信息的保存和心跳報(bào)文的發(fā)送??蛻舳瞬捎肞2P方式實(shí)現(xiàn)消息傳遞,并能實(shí)現(xiàn)文件的傳輸。本文首先討論了同步套接字,異步套接字,多線程并發(fā)執(zhí)行任務(wù)等;然后闡述了客戶端、效勞器如何使用XML序列化的消息進(jìn)行通信。關(guān)鍵詞:即時(shí)通信;文件傳輸;套接字;TCP協(xié)議Abstract:Instantmessageshaveseveraladvantagessuchasreal-time,cross-platform,cheapandefficient.TodesignaMulti-userIM(instantmessage)architectureisveryimportantinboththeoryandrealism.InstantmessagebasedonTCP/IPprotocolthatisrealizedbysocketinterface.AlmostallUNIXoperationsystemsandMicrosoft'swindowsoperationsystemsprovidesupportofsocketinthekernel.Usingtheuniforminterface,wecandevelopaportableprogramofTCP/IP,whichhelpustransferinformationinInternetsafelyandcredibly.Thesystemusestheclient/server(C/S)mode.Theservertakestheresponsibilityoftheloginmessageofclient,thesavingoffriendmessageandMessageheartbeat.ThetransmissionofthebasicmessagesofthecustomerendwillbedesignedonP2Parchitecture.ThisthesisexplainshowtheclientandservercommunicateviaserializingXMLmessage.Keywords:InstantMessage;FileTransfer;Socket;TCPprotocol引言1.1課題背景即時(shí)通信是一個(gè)終端連往一個(gè)即時(shí)通信網(wǎng)路的效勞。即時(shí)通信不同于e-mail在于它的交談是實(shí)時(shí)的。大局部的即時(shí)通信效勞提供了presenceawareness的特性──顯示聯(lián)絡(luò)人名單,聯(lián)絡(luò)人是否在在線與能否與聯(lián)絡(luò)人交談。最早的即時(shí)通信軟件是ICQ,ICQ是英文中Iseekyou的諧音,意思是我找你。四名以色列青年于1996年7月成立Mirabilis公司,并在11月份發(fā)布了最初的ICQ版本,在六個(gè)月內(nèi)有85萬用戶注冊(cè)使用。在因特網(wǎng)上受歡送的即時(shí)通信效勞包含了MSNMessenger、AOLInstantMessenger、Yahoo!Messenger、NETMessengerService、Jabber、ICQ與QQ。這些效勞有賴于許多想法更久的(與普遍)的在線聊天媒介,如InternetRelayChat一樣知名。1970年代早期,一種更早的即時(shí)通信形式是柏拉圖系統(tǒng)(PLATOsystem)。之后在1980年代,UNIX/Linux的交談實(shí)時(shí)信息被廣泛的使用于工程師與學(xué)術(shù)界,1990年代即時(shí)通信更跨越了因特網(wǎng)交流。1996年11月,ICQ是首個(gè)廣泛被非UNIX/Linux使用者用于因特網(wǎng)的即時(shí)通信軟件。在ICQ的介紹之后,同時(shí)在許多地方有一定數(shù)量的即時(shí)通信方式開展,且各式的即時(shí)通信程序有獨(dú)立的協(xié)議,無法彼此互通。這引導(dǎo)使用者同時(shí)執(zhí)行兩個(gè)以上的即時(shí)通信軟件,或者他們可以使用支持多協(xié)議的終端軟件,如Gaim、Trillian或Jabber。1.2國內(nèi)外研究現(xiàn)狀國外研究現(xiàn)狀當(dāng)今,國際上對(duì)網(wǎng)絡(luò)通信系統(tǒng)研究的較好的公司有,思科,Sun,Ms等公司,思科主要研究的是底層的傳輸;MS,Sun公司研究的是應(yīng)用層。其中ms公司憑借其在操作系統(tǒng)的壟斷地位,為了在網(wǎng)絡(luò)的開展中取得先機(jī),采用了各種各樣的手段。但是,其捆綁的msn,無論從功能上,還是技術(shù)上來說,都不算是非常先進(jìn)的。當(dāng)然,ie,同樣也不是很受人青睞,這讓人想起了,當(dāng)年的網(wǎng)景公司,網(wǎng)景只是生不逢時(shí)。MS不擇手段的想打跨網(wǎng)景,可見其對(duì)網(wǎng)絡(luò)的重視。如今,Sun公司在網(wǎng)絡(luò)應(yīng)用上捷足先登,憑借著Java,Sun在網(wǎng)絡(luò)的應(yīng)用上領(lǐng)先于MS。微軟,想用同樣的方法搞跨對(duì)手,因此它拿出了Visualc#,來對(duì)抗Java。這些都是在應(yīng)用層面的開發(fā)工具。應(yīng)用層上的產(chǎn)品就更顯種類繁多。ICQ幾乎是國際上通用的即時(shí)通信工具,由于在我國它的應(yīng)用不是很廣,所以,其原理也很少被介紹。msn,是MS的產(chǎn)品,同樣在國內(nèi)沒什么市場(chǎng),所以,對(duì)其原理,也很少被討論過。至于ie,是在Visualc++下開發(fā)的產(chǎn)品,雖然有嚴(yán)重的平安隱患,不過,至少能在某種程度上代表當(dāng)今國際研究的水平。此外,國際上最近出先了新的瀏覽器Firefox,其性能據(jù)說是遠(yuǎn)高于ie,也許在網(wǎng)絡(luò)的天下,Ms又有了更強(qiáng)勁的對(duì)手。國內(nèi)研究現(xiàn)狀國內(nèi)在應(yīng)用層上的網(wǎng)絡(luò)應(yīng)用軟件目前開展異常的火爆,因?yàn)槲覈兄W(wǎng)絡(luò)應(yīng)用的最大的市場(chǎng),現(xiàn)在國內(nèi)網(wǎng)絡(luò)的根底性建設(shè)開展迅速,應(yīng)用軟件也層出不窮,其中,在游戲的領(lǐng)域中,網(wǎng)絡(luò)通信的工作做的不錯(cuò),如聯(lián)眾游戲平臺(tái),還有其他的一些平臺(tái),這些平臺(tái)根本上都是基于VC++的,用的都是Socket通信,但是為了效率,這些平臺(tái)沒有用MFC提供的CSocket類,而是直接用Socket進(jìn)行通信。所以效率上不錯(cuò)。此外,tencent的即時(shí)通信,也是做的很好的,從某中程度上來說,代表了國內(nèi)最高的水平。1.3本課題的研究方法本系統(tǒng)采用C/S〔Client/Server〕結(jié)構(gòu)進(jìn)行設(shè)計(jì),使用SQLServer2000構(gòu)建數(shù)據(jù)庫,并在.NET環(huán)境下使用VisualC#.net語言和SOCKET套接字開發(fā)一個(gè)基于TCP協(xié)議的簡(jiǎn)單即時(shí)通信軟件,實(shí)現(xiàn)簡(jiǎn)單的即時(shí)聊天,文件傳輸?shù)裙δ堋?相關(guān)技術(shù)介紹2.1.NET開發(fā)平臺(tái)及C#.NET開發(fā)語言NET框架是Microsoft公司推出的一種全新的開發(fā)平臺(tái),提供了統(tǒng)一的、面向?qū)ο蟛⑶铱梢詳U(kuò)展的編程類庫和完善的集成開發(fā)環(huán)境,大大簡(jiǎn)化了應(yīng)用程序的開發(fā)過程,并且具有良好的移植性和平安性。微軟為了推行.NET戰(zhàn)略,特別為.NET平臺(tái)設(shè)計(jì)了一種語言——C#。C#是由C和C++派生而來的一種“簡(jiǎn)單、流行、面向?qū)ο?、類型平安〞的程序設(shè)計(jì)語言,其綜合了Visualbasic的高效率和C++的強(qiáng)大功能,然而更多的人感覺C#更類似JAVA。2.2TCP協(xié)議TCP/IP網(wǎng)絡(luò)協(xié)議協(xié)議是對(duì)等的網(wǎng)絡(luò)實(shí)體之間通信的規(guī)那么,可以簡(jiǎn)單地理解為網(wǎng)絡(luò)上各計(jì)算機(jī)彼此交流的一種“語言〞。網(wǎng)絡(luò)通信協(xié)議設(shè)計(jì)的根本原那么是層次化,層和協(xié)議的集合被稱為網(wǎng)絡(luò)體系結(jié)構(gòu)。相鄰層之間的接口定義了下層向上層提供的根本操作和效勞,下層向上層提供的效勞分兩種形式:面向連接的效勞和無連接的效勞。計(jì)算機(jī)網(wǎng)絡(luò)中已經(jīng)形成的網(wǎng)絡(luò)體系結(jié)構(gòu)主要有兩個(gè):OSI參考模型和TCP/IP參考模型。TCP/IP參考模型是因特網(wǎng)〔Internet〕的根底。和OSI的7層協(xié)議相比,TCP/IP協(xié)議只有4個(gè)層次。通常說的TCP/IP是一組協(xié)議的總稱,TCP/IP實(shí)際上是一個(gè)協(xié)議族,包括100多個(gè)相互關(guān)聯(lián)的協(xié)議,其中IP(InternetProtocol,網(wǎng)際協(xié)議)是網(wǎng)絡(luò)層最主要的協(xié)議;TCP(TransmissionControlProtocol,傳輸控制協(xié)議)和UDP(UserDatagramProtocol,用戶數(shù)據(jù)報(bào)協(xié)議是傳輸層中最主要的協(xié)議),一般認(rèn)為IP、TCP、UDP是最根本的三種協(xié)議,是其他協(xié)議的根底。TCP——傳輸控制協(xié)議:面向連接的通信可以使用可靠通信,在這時(shí)候,第四層協(xié)議發(fā)送數(shù)據(jù)接收方確實(shí)認(rèn),如果未收到數(shù)據(jù)或者數(shù)據(jù)被損壞,那么請(qǐng)求重新傳輸。TCP協(xié)議就使用這種可靠通信。使用TCP協(xié)議的應(yīng)用層協(xié)議包括HTTP、FTP、SMTP和Telnet等?,F(xiàn)在可以發(fā)送和接收消息了。接收消息后,總是返回ACK消息。如果在收到ACK之前發(fā)送方已經(jīng)超時(shí),那么消息將被放到重發(fā)隊(duì)列中以再次發(fā)送。由于它的握制,所以TCP協(xié)議比擬復(fù)雜并且費(fèi)時(shí),但此協(xié)議在處理數(shù)據(jù)時(shí)對(duì)數(shù)據(jù)包的傳送有保障,從而使得在應(yīng)用程序協(xié)議中不需要再包括該功能。2.3套接字套接字這個(gè)術(shù)語并沒有定義某個(gè)協(xié)議:它具有兩層含義,但兩者都與一個(gè)協(xié)議相關(guān)。第一個(gè)含義是套接字編程API,它最初由伯克利大學(xué)為BSDUNIX而創(chuàng)立。BSD套接字在經(jīng)過修改后被用作Windows環(huán)境的編程接口〔并且被命名為WinSock〕。WinSockAPI被包裝在System.Net.sockets命名空間的.NET類中。WindowsSockets是一個(gè)獨(dú)立于協(xié)議的編程接口,用于編寫網(wǎng)絡(luò)應(yīng)用程序。2.4流流的根本概念流的概念已經(jīng)存在很長(zhǎng)時(shí)間了。流是一個(gè)用于傳輸數(shù)據(jù)的對(duì)象。數(shù)據(jù)的傳輸有兩個(gè)方向:1)如果數(shù)據(jù)從外部源傳輸?shù)匠绦蛑校@就是讀取流。2)如果數(shù)據(jù)從程序傳輸?shù)酵獠吭矗@就是寫入流。外部源常常是一個(gè)文件,但也不完全都是文件,它還可以是:1)網(wǎng)絡(luò),使用一定的網(wǎng)絡(luò)協(xié)議與網(wǎng)絡(luò)上其它計(jì)算機(jī)或終端交換數(shù)據(jù)。2〕一個(gè)指定的管道。3)一塊內(nèi)存區(qū)域。2.5同步、異步、阻塞和非阻塞同步〔synchronous〕:所謂同步方式,就是發(fā)送方發(fā)送數(shù)據(jù)包以后,不等接受方響應(yīng),就接著發(fā)送下一個(gè)數(shù)據(jù)包。異步〔asynchronous〕:異步方式就是當(dāng)發(fā)送方發(fā)送一個(gè)數(shù)據(jù)包以后,一直等到接受方響應(yīng)后,才接著發(fā)送下一個(gè)數(shù)據(jù)包。阻塞〔Block〕:指執(zhí)行此套接字的網(wǎng)絡(luò)調(diào)用時(shí),直到調(diào)用成功才返回,否那么此套節(jié)字就一直阻塞在網(wǎng)絡(luò)調(diào)用上,比方調(diào)用StreamReader類的Readlin()方法讀取網(wǎng)絡(luò)緩沖區(qū)中的數(shù)據(jù),如果調(diào)用的時(shí)候沒有數(shù)據(jù)到達(dá),那么此Readlin()方法將一直掛在調(diào)用上,直到讀到一些數(shù)據(jù),此函數(shù)調(diào)用才返回。非阻塞〔Unblock〕:指在執(zhí)行此套接字的網(wǎng)絡(luò)調(diào)用時(shí),不管是否執(zhí)行成功,都立即返回。同樣調(diào)用StreamReader類的Readlin()方法讀取網(wǎng)絡(luò)緩沖區(qū)中數(shù)據(jù),不管是否讀到數(shù)據(jù)都立即返回,而不會(huì)一直掛在此函數(shù)調(diào)用上。在Windows網(wǎng)絡(luò)通信軟件開發(fā)中,最為常用的方法就是異步非阻塞套接字。平常所說的C/S〔客戶端/效勞器〕結(jié)構(gòu)的軟件采用的方式就是異步非阻塞模式的。其實(shí)在用C#進(jìn)行網(wǎng)絡(luò)編程中,我們并不需要了解什么同步、異步、阻塞和非阻塞的原理和工作機(jī)制,因?yàn)樵?NetFrameWrokSDK中已經(jīng)已經(jīng)把這些機(jī)制給封裝好了。3.系統(tǒng)總體設(shè)計(jì)3.1需求分析軟件針對(duì)局域網(wǎng)內(nèi)部用戶,實(shí)現(xiàn)用戶間的即時(shí)通信。需要分別實(shí)現(xiàn)效勞器端和客戶端的軟件設(shè)計(jì)。效勞器端負(fù)責(zé)監(jiān)聽用戶連接請(qǐng)求,負(fù)責(zé)連接數(shù)據(jù)庫存儲(chǔ)用戶信息,負(fù)責(zé)發(fā)送給用戶好友信息,負(fù)責(zé)發(fā)送心跳報(bào)文檢查用戶在線狀態(tài)并即時(shí)讓用戶更新好友在新信息。客戶端發(fā)起主動(dòng)連接,向效勞器請(qǐng)求登錄或者注冊(cè)。客戶端可以修改昵稱,可以加用戶為好友〔類似于MSN的好友添加功能〕。客戶端之間可以發(fā)起P2P模式的聊天,可以傳送文件。3.2系統(tǒng)根本架構(gòu)基于C/S架構(gòu)的即時(shí)通信軟件便于對(duì)用戶信息進(jìn)行統(tǒng)一管理和保存,面向特定的用戶,對(duì)信息的平安控制能力很強(qiáng)。為了減輕效勞器負(fù)擔(dān),客戶端之間的信息傳遞是采用P2P模式的,效勞器只負(fù)責(zé)用戶的注冊(cè),登錄和用戶在線狀態(tài)的檢驗(yàn)。根本結(jié)構(gòu)如圖:3.3功能模塊設(shè)計(jì)CLIENT:1.注冊(cè):(1)可以完成客戶端注冊(cè),客戶端可以通過填寫信息進(jìn)行注冊(cè),信息被發(fā)送到效勞器端。2.登錄:(1)客戶可以輸入賬號(hào)和密碼進(jìn)行登錄,客戶端會(huì)發(fā)送登錄信息等待效勞器響應(yīng),登錄成功后會(huì)發(fā)出登錄成功信息并刷新好友列表。3.修改:(1)密碼修改:應(yīng)該有密碼修改功能(2)信息修改:可以更改一些注冊(cè)信息4.通信:(1)即時(shí)聊天模塊:客戶端與客戶端之間建立線程進(jìn)行即時(shí)聊天,也包含有簡(jiǎn)單的對(duì)稱加解密算法功能。(2)好友列表:可以對(duì)好友列表進(jìn)行添加刪除等動(dòng)作。5.文件傳輸:(1)文件傳輸:文件傳輸功能SERVER:注冊(cè)回應(yīng):對(duì)客戶端傳送的注冊(cè)信息進(jìn)行判斷。(1)HASH加密:對(duì)用戶的賬號(hào)和密碼信息進(jìn)行HASH加密(2)重復(fù)用戶檢查:將加密后信息與已存在賬號(hào)進(jìn)行比擬,檢查是否賬號(hào)已存在,如果存在就返回錯(cuò)誤信息〔3)注冊(cè)成功:將可成功注冊(cè)的用戶賬號(hào)和密碼寫入數(shù)據(jù)庫內(nèi),并向客戶端返回成功信息2.修改回應(yīng):(1)對(duì)密碼和信息修改請(qǐng)求進(jìn)行判斷,執(zhí)行和返回修改成功信息。3.登錄回應(yīng):(1)對(duì)登錄的賬號(hào)和密碼進(jìn)行加密檢查后發(fā)回正確或錯(cuò)誤情況,并記錄上線信息。(2)好友列表發(fā)送:給成功登錄的賬號(hào)發(fā)送好友列表及好友上線信息。(3)上線信息發(fā)送:給成功登錄的賬號(hào)的好友發(fā)送在線信息〔包括IP,端口等等信息〕。4.在線情況:(1)對(duì)登錄,在線,離線的用戶情況進(jìn)行統(tǒng)計(jì),記錄和通知(2)心跳測(cè)試:每隔一段時(shí)間發(fā)送報(bào)文測(cè)試用戶是否因意外原因離線(3)情況記錄:將用戶登錄時(shí)間,IP,下線時(shí)間等信息記錄入數(shù)據(jù)庫3.4邏輯圖:3.5數(shù)據(jù)庫設(shè)計(jì)實(shí)體關(guān)系圖效勞器是作為記錄和讀取數(shù)據(jù)庫信息的載體,與客戶端關(guān)系并不復(fù)雜,這里需要重點(diǎn)考慮客戶端之間的關(guān)系。用戶與用戶之間的關(guān)系是較為特殊的遞歸關(guān)系,即描述發(fā)生在兩個(gè)相同實(shí)體上的關(guān)系。4系統(tǒng)實(shí)現(xiàn)4.1使用XML定義的即時(shí)通信協(xié)議信息結(jié)構(gòu)MESSAGE.CS&UMESSAGE.CS這兩個(gè)C#類定義了包括效勞器信息,狀態(tài)信息,注冊(cè)信息,登錄信息,聊天信息或者請(qǐng)求文件傳輸信息的函數(shù),效勞器和客戶端通過將它們實(shí)例化和序列化再轉(zhuǎn)換成流在網(wǎng)絡(luò)上進(jìn)行傳輸。UMESSAGE.CS主要代碼如下:[Serializable]publicclassUMessage{publicUMessage(){}privatestring_nickname;privatestring_password;privatestring_accounts;privatestring_email;privateint_info;//表示注冊(cè)或者登錄信息,客戶端信息0為注冊(cè),1為登錄;效勞器返回信息0為用戶已存在,1為注冊(cè)成功,2為效勞器未知錯(cuò)誤,3為CLIENT在線檢查,10為登錄失敗,11為登錄成功privateFriend[]_friend;privateint_fn;privatestring_fg;publicstringNickname{get{return_nickname;}set{_nickname=value;}}publicstringPassword{get{return_password;}set{_password=value;}}publicstringAccounts{get{return_accounts;}set{_accounts=value;}}publicstringEmail{get{return_email;}set{_email=value;}}publicintInfo{get{return_info;}set{_info=value;}}publicFriend[]Fri{get{return_friend;}set{_friend=value;}}publicintFn{get{return_fn;}set{_fn=value;}}publicstringFg{get{return_fg;}set{_fg=value;}}}由于MESSAGE.CS與UMESSAGE.CS類似,在此不再詳述。效勞器和客戶端都可以通過相同的代碼對(duì)UMESSAGE賦值,再通過XmlSerializer方法進(jìn)行將UMESSAGE序列化為XML文檔,最后將XML文檔轉(zhuǎn)化為網(wǎng)絡(luò)流進(jìn)行傳輸。代碼如下:#region將登錄信息轉(zhuǎn)為UMessageprivatevoidTraslator(){_message.Accounts=this.TextBox1.Text;_message.Nickname="";_message.Password=this.TextBox2.Text;_message.Email="";_message.Info=1;_message.Fri=null;}#endregion數(shù)據(jù)結(jié)構(gòu)FriendStruct效勞器如果保存和傳遞用戶的好友信息是難點(diǎn)之一。數(shù)據(jù)庫的設(shè)計(jì)和信息的傳遞區(qū)分都是比擬難實(shí)現(xiàn)的。在數(shù)據(jù)庫方面,每個(gè)用戶擁有各自的好友分組信息〔UserFav〕,分組中間使用“,〞分隔,在TCP_FriendInfo表中那么分別保存了用戶ID和好友ID,使用一個(gè)INT字段保存分組信息。數(shù)據(jù)庫以用戶ID為標(biāo)準(zhǔn)對(duì)好友ID和分組信息進(jìn)行內(nèi)連接查詢,就可以得到根本的好友信息了。代碼如下:select*fromTCP_UserInfojoinTCP_FriendInfoonTCP_FriendInfo.UserID='"+uid+"'andTCP_UserInfo.UserID=TCP_FriendInfo.FriendID在好友信息的傳輸方面,首先定義一個(gè)FriendStruct數(shù)據(jù)結(jié)構(gòu)〔當(dāng)然也可以用枚舉完成〕如下:usingSystem;usingSystem.Collections.Generic;usingSystem.Text;namespaceTCP{publicclassFriendStruct{publicstructFileInfo{publicintfilere;//接收和拒絕信息,1為接收,2為拒絕,3為取消publicstringfilename;publiclongfilelength;}}publicstructFriend{publicstringaccount;publicstringnickname;publicstringIP;publicstringstatus;publicstringfg;//好友分組}}在MESSAGE.CS或者UMESSAGE.CS中,我們那么定義了FriendStruct的數(shù)組。在C#中使用DATAREADER語句可以逐句讀取數(shù)據(jù)庫查詢的結(jié)果,再依次將結(jié)果賦值FriendStruct數(shù)組元素,就得到了便于發(fā)送和讀取的存放好友信息的數(shù)組。賦值代碼如下:while(getf.Read())//getf即是以上的數(shù)據(jù)庫查詢的datareader語句{ff[i].account=getf["UserAccount"].ToString();ff[i].IP=getf["UserIP"].ToString();ff[i].nickname=getf["UserNickname"].ToString();ff[i].status=getf["UserOnline"].ToString();ff[i].fg=getf["FriendGroup"].ToString();i++;}getf.Close();4.2數(shù)據(jù)庫連接類實(shí)現(xiàn)一個(gè)快捷簡(jiǎn)單的數(shù)據(jù)庫連接的相關(guān)代碼是非常有必要的。實(shí)現(xiàn)的途徑也多種多樣,鑒于平安性和復(fù)雜性的需求不同,實(shí)現(xiàn)方法有簡(jiǎn)有繁。本設(shè)計(jì)使用了一個(gè)簡(jiǎn)單的類〔UserData.CS〕實(shí)現(xiàn)了簡(jiǎn)單快捷的數(shù)據(jù)庫連接和讀取。主要代碼如下:publicstaticSqlConnectionconnStr=newSqlConnection("Server=D96B85DD938A465.;uid=sa;pwd=change;database=TCPDB");publicstaticSqlDataReaderSqlReader(stringsql,SqlConnectionconnstr){SqlDataReadersqldr=null;SqlCommandcmd=newSqlCommand(sql,connstr);if(cmd.Connection.State.ToString()=="Closed")cmd.Connection.Open();try{sqldr=cmd.ExecuteReader();}catch(Exceptione){catch(Exceptione){if(e!=null)sqldr=null;}returnsqldr;}//數(shù)據(jù)庫操作連接publicstaticstringSqlCmd(stringsql,SqlConnectionconnstr){stringerrorstr=null;SqlCommandsqlcmd=newSqlCommand(sql,connstr);if(sqlcmd.Connection.State.ToString()=="Open")sqlcmd.Connection.Close();sqlcmd.Connection.Open();try{sqlcmd.ExecuteNonQuery();}catch(Exceptione){if(e!=null)errorstr=e.ToString();}sqlcmd.Connection.Close();returnerrorstr;}在UserData.CS的根底上,主程序可以更方便地實(shí)現(xiàn)數(shù)據(jù)庫連接操作,對(duì)數(shù)據(jù)庫進(jìn)行讀寫和更新,在此不再詳述。4.3效勞器端效勞器端的界面設(shè)計(jì)是基于便于測(cè)試的目的而實(shí)現(xiàn)的。如下列圖:同步套接字網(wǎng)絡(luò)監(jiān)聽基于同步套接字的網(wǎng)絡(luò)監(jiān)聽器對(duì)效勞器來說并不是最好的解決方案,但是仍然可行并且實(shí)現(xiàn)簡(jiǎn)單。主要代碼如下:開啟監(jiān)聽端口:publicvoidServe(){intport=8888;ServerIPEP=newIPEndPoint(IPAddress.Any,port);s=newSocket(ServerIPEP.AddressFamily,SocketType.Stream,ProtocolType.Tcp);s.Bind((EndPoint)ServerIPEP);s.Listen(10);alSock=newArrayList();以下代碼讀取連入的連接,依次將連接參加可變長(zhǎng)數(shù)組alsock,并且讀取傳入的信息,進(jìn)行反串行化:while(true){try{uc=s.Accept();alSock.Add(uc);this.tb_states.AppendText(System.Convert.ToString(uc));byte[]data=newbyte[2048];intrect=uc.Receive(data);byte[]chat=newbyte[rect];Buffer.BlockCopy(data,0,chat,0,rect);UMessageumessage=(UMessage)_translator.Deserialize(newMemoryStream(chat));intinfo=umessage.Info;對(duì)反串行化后的信息進(jìn)行處理,通過info參數(shù)識(shí)別客戶端行為〔注冊(cè)或者登錄〕,對(duì)注冊(cè)的信息進(jìn)行數(shù)據(jù)庫查詢,注冊(cè)信息可插入,那么將用戶信息插入數(shù)據(jù)庫,否那么返回客戶端“注冊(cè)出錯(cuò)〞的信息:#region處理用戶注冊(cè)信息if(info==0)//分辨出用戶發(fā)送的是注冊(cè)信息{stringAccounts=umessage.Accounts;SqlDataReaderusdr=FPara.SqlReader("select*fromTCP_UserInfowhereUserAccount='"+Accounts+"'",FPara.connStr);if(usdr!=null){if(usdr.Read()){#region此處寫入返回注冊(cè)失敗的代碼Socketsc=(Socket)alSock[alSock.IndexOf(uc,0)];sc.Send(chat);#endregion}else{#region此處寫入插入數(shù)據(jù)庫用戶注冊(cè)信息的代碼Streamms=newMemoryStream();Socketsc=(Socket)alSock[alSock.IndexOf(uc,0)];if(FPara.SqlCmd("insertintoTCP_UserInfo(UserAccount,UserNickname,UserEmail,JoinDate,UserIP,UserPassword)values('"+umessage.Accounts+"','"+umessage.Nickname+"','"+umessage.Email+"','"+System.DateTime.Now.ToString()+"','"+((IPEndPoint)uc.RemoteEndPoint).Address.ToString()+"','"+umessage.Password+"')",FPara.connStr)==null){umessage.Info=1;_translator.Serialize(ms,umessage);byte[]d=newbyte[ms.Length];ms.Seek(0,SeekOrigin.Begin);ms.Read(d,0,d.Length);sc.Send(d);}else{umessage.Info=2;_translator.Serialize(ms,umessage);byte[]d=newbyte[ms.Length];ms.Seek(0,SeekOrigin.Begin);ms.Read(d,0,d.Length);sc.Send(d);}#endregion}usdr.Close();}}#endregion如果發(fā)現(xiàn)用戶發(fā)送的是登錄信息,就根據(jù)登錄信息中的用戶名和密碼判斷是否存在用戶,密碼是否正確,成功后再查詢出用戶的好友信息并且賦值給FriendStruct,再將信息返回給客戶端:#region處理用戶登錄信息elseif(info==1)//分辨出用戶發(fā)送的是登錄信息stringAccounts=umessage.Accounts;stringPassword=umessage.Password;SqlDataReaderusdr=FPara.SqlReader("select*fromTCP_UserInfowhereUserAccount='"+Accounts+"'andUserPassword='"+Password+"'",FPara.connStr);if(usdr!=null){if(usdr.Read()){stringuid=usdr["UserID"].ToString();umessage.Fg=usdr["UserFav"].ToString();usdr.Close();SqlDataAdaptersdr=newSqlDataAdapter("select*fromTCP_UserInfojoinTCP_FriendInfoonTCP_FriendInfo.UserID='"+uid+"'andTCP_UserInfo.UserID=TCP_FriendInfo.FriendID",FPara.connStr);DataSetds=newDataSet();sdr.Fill(ds,"find");intxxx=ds.Tables["find"].Rows.Count;FPara.SqlCmd("updateTCP_UserInfosetUserIP='"+((IPEndPoint)uc.RemoteEndPoint).Address.ToString()+"',UserOnline=1whereUserAccount='"+Accounts+"'",FPara.connStr);ff=newFriend[xxx];inti=0;SqlDataReadergetf=FPara.SqlReader("select*fromTCP_UserInfojoinTCP_FriendInfoonTCP_FriendInfo.UserID='"+uid+"'andTCP_UserInfo.UserID=TCP_FriendInfo.FriendID",FPara.connStr);while(getf.Read()){ff[i].account=getf["UserAccount"].ToString();ff[i].IP=getf["UserIP"].ToString();ff[i].nickname=getf["UserNickname"].ToString();ff[i].status=getf["UserOnline"].ToString();ff[i].fg=getf["FriendGroup"].ToString();i++;}getf.Close();#region此處寫入登錄成功代碼Streamms=newMemoryStream();Socketsc=(Socket)alSock[alSock.IndexOf(uc,0)];this.lb_users.Items.Add(alSock.IndexOf(uc).ToString());umessage.Info=11;umessage.Fri=ff;umessage.Fn=xxx;_translator.Serialize(ms,umessage);byte[]d=newbyte[ms.Length];ms.Seek(0,SeekOrigin.Begin);ms.Read(d,0,d.Length);sc.Send(d);//在tb_status中寫入效勞器返回給客戶端的代碼便于測(cè)試觀察this.tb_states.AppendText(System.Text.Encoding.Default.GetString(d));#endregion}else{usdr.Close();#region此處寫入登錄失敗代碼Streamms=newMemoryStream();Socketsc=(Socket)alSock[alSock.IndexOf(uc,0)];umessage.Info=10;_translator.Serialize(ms,umessage);byte[]d=newbyte[ms.Length];ms.Seek(0,SeekOrigin.Begin);ms.Read(d,0,d.Length);sc.Send(d);#endregion}}}#endregionTb_states是個(gè)用于監(jiān)視SOCKET傳入信息的文本框,便于觀察和測(cè)試相關(guān)信息:this.tb_states.AppendText("["+uc.RemoteEndPoint.ToString()+"]"+System.Text.Encoding.Default.GetString(chat));}catch(Exceptionex){MessageBox.Show(ex.Message);}}}以上代碼也包含了對(duì)客戶端的請(qǐng)求信息的判斷和對(duì)客戶端返回信息的生成和傳輸。多線程對(duì)于效勞器來說,多線程是必不可少的,否那么它將無法處理不斷請(qǐng)求的新連接。C#的System.Threading提供了多線程編程的支持。本設(shè)計(jì)實(shí)現(xiàn)代碼如下:this.th=newThread(newThreadStart(Serve));//新建一個(gè)用于監(jiān)聽的線程th.Start();//翻開新線程不僅僅是效勞器,基于P2P模式聊天的客戶端也必須支持多線程運(yùn)行,實(shí)現(xiàn)代碼與之類似,在客戶端設(shè)計(jì)說明中將不再表達(dá)。計(jì)時(shí)器計(jì)時(shí)器用于實(shí)現(xiàn)心跳報(bào)文的功能,效勞器在啟動(dòng)以后就開始計(jì)時(shí),每隔一定時(shí)間就向所有連入的客戶端發(fā)送信息,核心代碼如下://用計(jì)時(shí)器檢查客戶端是否掉線aTimer=newSystem.Timers.Timer();aTimer.Elapsed+=newElapsedEventHandler(CheckStatus);//設(shè)置引發(fā)時(shí)間的時(shí)間間隔此處設(shè)置為5秒〔5000毫秒〕aTimer.Interval=5000;aTimer.Enabled=true;CheckStatus就是用于向客戶端發(fā)送檢查信息的方法,它會(huì)向遍歷連入的客戶端(alSock),然后依次向客戶端發(fā)送信息,如果發(fā)現(xiàn)客戶端沒有響應(yīng),就會(huì)如果發(fā)現(xiàn)對(duì)方無回應(yīng),那么關(guān)閉相應(yīng)的SOCKET,并更新數(shù)據(jù)庫的用戶在線狀態(tài),同時(shí)向該用戶的所有好友發(fā)送用戶已下線的通知。4.4客戶端4.4客戶端圖5注冊(cè)界面圖6登錄、聊天、文件傳輸界面同步套接字客戶端客戶端發(fā)起同步套接字連接,并傳送登錄或者注冊(cè)信息,由于兩者方式類似,這里僅列出用戶登錄的代碼:#region發(fā)送效勞器登錄信息,并接收效勞器反應(yīng)信息publicvoidClient(){建立SOCKET發(fā)送信息:try{IPEndPointServerIPEP=newIPEndPoint(IPAddress.Parse("6"),8888);c=newSocket(ServerIPEP.AddressFamily,SocketType.Stream,ProtocolType.Tcp);c.Connect((EndPoint)ServerIPEP);s=newMemoryStream();_translator.Serialize(s,_message);byte[]d=newbyte[s.Length];s.Seek(0,SeekOrigin.Begin);s.Read(d,0,d.Length);inti=c.Send(d,0,d.Length,SocketFlags.None);}catch(Exceptionex){MessageBox.Show(ex.Message);}以下代碼讀取了效勞器返回給客戶端的信息〔注冊(cè)和登錄的成功與失敗〕,如果返回了登錄成功的信息,還會(huì)讀取效勞器給出的FriendStruct結(jié)構(gòu)以得到用戶的好友信息:#region接收反應(yīng)信息byte[]data=newbyte[2048];while(true){intrect=c.Receive(data);byte[]chat=newbyte[rect];Buffer.BlockCopy(data,0,chat,0,rect);UMessagebumessage=(UMessage)_translator.Deserialize(newMemoryStream(chat));string[]fg;string_fg=bumessage.Fg;if(bumessage.Info==3){}elseif(bumessage.Info==11){fg=_fg.Split(',');intxxx=bumessage.Fn;ff=bumessage.Fri;for(inti=0;i<xxx;i++){string[]ems=newstring[5];ems[0]=ff[i].account;ems[1]=ff[i].nickname;ems[2]=fg[int.Parse(ff[i].fg)];ems[3]=ff[i].IP;ems[4]=ff[i].status;ListViewItemitem=newListViewItem(ems);this.listView1.Items.Add(item);}CSERVER是一個(gè)用于開啟監(jiān)聽P2P信息的方法,客戶端在登錄成功以后就會(huì)立刻開啟監(jiān)聽器,才能夠?qū)崿F(xiàn)與其它客戶端的聊天:Th=newThread(newThreadStart(CServer));//新建一個(gè)用于監(jiān)聽其它客戶端信息的線程th.Start();//翻開新線程MessageBox.Show(bumessage.Accounts+"登錄成功!");this.Button1.Enabled=false;this.Button3.Enabled=false;}elseif(bumessage.Info==2){MessageBox.Show("效勞器未知錯(cuò)誤");}else{MessageBox.Show(bumessage.Info.ToString());}}#endregion}#endregion客戶端之間的聊天同樣使用了序列化的XML文檔,用戶在登錄成功后就會(huì)啟動(dòng)一個(gè)新的監(jiān)聽器去監(jiān)聽其它客戶端傳入的聊天信息并且進(jìn)行判斷再將其它用戶的聊天信息顯示在界面上。這里也不再闡述代碼。.4.2采用異步套接字的文件傳輸文件傳輸是通過一個(gè)類庫實(shí)現(xiàn)的。由于文件傳輸?shù)拇a實(shí)現(xiàn)復(fù)雜,通過類庫可以大量的簡(jiǎn)化代碼,使主程序簡(jiǎn)潔易懂。類庫Infinity.Networking包括了ClientBase.cs,ClientInfo.cs,Delegates.cs,INPClient.cs,INPServer.cs,ClientBase.cs定義了根底的文件發(fā)送函數(shù),INPClient.cs那么僅包含初始化文件發(fā)送的函數(shù);ServerBase.cs和INPServer.cs那么是反之亦然。核心代碼如下:ClientBase.cs:這個(gè)類實(shí)現(xiàn)了套接字的開啟和數(shù)據(jù)的傳輸ClientBase.cs:這個(gè)類實(shí)現(xiàn)了套接字的開啟和數(shù)據(jù)的傳輸usingSystem;usingSystem.Net;usingSystem.Net.Sockets;namespaceInfinity.Networking{///<summary>///ClientBase摘要.///</summary>publicclassClientBase{privateconstintBUFFERSIZE=4*1024;privateint_port;privatestring_serverIP;privateSocket_mainSoc;privateClientInfo_info;privateAsyncCallback_dataRecievedCallback;//異步回調(diào)方法publiceventNetworkEventHandlerDataRecieved;//定義一個(gè)事件:接收到數(shù)據(jù)時(shí)引發(fā)事件publicClientBase(stringserverIP,intport){_serverIP=serverIP;_port=11000;_mainSoc=newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);_info=newClientInfo(_mainSoc,newbyte[BUFFERSIZE]);//ClientInfo包含了建立的套接字和套
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 醫(yī)療護(hù)理倫理與公共衛(wèi)生-洞察分析
- 5G時(shí)代下的工業(yè)互聯(lián)網(wǎng)與智能制造技術(shù)探討
- 辦公環(huán)境下的寶寶成長(zhǎng)提升工作與學(xué)習(xí)效率
- 從生命科學(xué)到醫(yī)療技術(shù)的創(chuàng)新與發(fā)明探討
- 辦公室文化積極工作氛圍的營造
- 以繪本為媒介的親子溝通方法研究
- 2025石材切邊承包合同
- 健康飲食習(xí)慣在現(xiàn)代商業(yè)環(huán)境中的價(jià)值
- 2025年高性能石膏板市場(chǎng)分析報(bào)告
- 2021-2026年中國木材海運(yùn)行業(yè)發(fā)展監(jiān)測(cè)及投資戰(zhàn)略規(guī)劃研究報(bào)告
- 重難點(diǎn)專題41 圓錐曲線中定比點(diǎn)差法的應(yīng)用十一大題型-備戰(zhàn)2025年高考《數(shù)學(xué)》重難點(diǎn)題型突破(新高考)解析版
- S學(xué)習(xí)問題個(gè)性化分析診斷系統(tǒng)v2.0 分析標(biāo)準(zhǔn)
- 因式分解法一元二次方程練習(xí)100題及答案
- 產(chǎn)品逆向設(shè)計(jì)智慧樹知到期末考試答案章節(jié)答案2024年武漢職業(yè)技術(shù)學(xué)院
- 人音版 一年級(jí)上冊(cè)《國旗國旗真美麗》(教案)
- 上海生活垃圾分類現(xiàn)狀調(diào)查報(bào)告
- 房屋退還協(xié)議書范本
- 《數(shù)與形》(教案)2023-2024學(xué)年數(shù)學(xué)六年級(jí)上冊(cè)
- 北京市東城區(qū)2023-2024學(xué)年八年級(jí)上學(xué)期期末生物試題【含答案解析】
- 江蘇省南京市選調(diào)生考試(行政職業(yè)能力測(cè)驗(yàn))綜合能力題庫含答案
- 幼兒園勞動(dòng)教育國內(nèi)外研究現(xiàn)狀
評(píng)論
0/150
提交評(píng)論