基于Linux網(wǎng)絡(luò)聊天室的方案設(shè)計(jì)書_第1頁
基于Linux網(wǎng)絡(luò)聊天室的方案設(shè)計(jì)書_第2頁
基于Linux網(wǎng)絡(luò)聊天室的方案設(shè)計(jì)書_第3頁
基于Linux網(wǎng)絡(luò)聊天室的方案設(shè)計(jì)書_第4頁
基于Linux網(wǎng)絡(luò)聊天室的方案設(shè)計(jì)書_第5頁
已閱讀5頁,還剩19頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

姓名:方建學(xué)號(hào):109074359班級(jí):網(wǎng)絡(luò)工程1031背景開發(fā)背景在網(wǎng)絡(luò)無所不在的今天,在Internet上,有ICQ、MSN、Gtalk、OICQ等網(wǎng)絡(luò)聊天軟件,極大程度上方便了處于在世界各地的友人之間的相互聯(lián)系,也使世界好像一下子縮小了,不管你在哪里,只要你上了網(wǎng),打開這些軟件,就可以給你的朋友發(fā)送信息,不管對方是否也同時(shí)在線,只要知道他有號(hào)碼。Linux操作系統(tǒng)作為一個(gè)開源的操作系統(tǒng)被越來越多的人所應(yīng)用,它的好處在于操作系統(tǒng)源代碼的公開化!只要是基于GNU公約的軟件你都可以任意使用并修改它的源代碼。但對很多習(xí)慣于Windows操作系統(tǒng)的人來說,Linux的操作不夠人性化、交互界面不夠美觀,這給Linux操作系統(tǒng)的普及帶來了很大的阻礙。因此制作一個(gè)Linux操作系統(tǒng)下的擁有人性化界面的實(shí)時(shí)通訊工具,將給那些剛剛接觸Linux操作系統(tǒng)的用戶帶來極大的方便,而且通過設(shè)計(jì)這樣的一個(gè)應(yīng)用程序還能更好的學(xué)習(xí)網(wǎng)絡(luò)編程知識(shí)和掌握LINUX平臺(tái)上應(yīng)用程序設(shè)計(jì)開發(fā)的過程,將大學(xué)四年所學(xué)知識(shí)綜合運(yùn)用,以達(dá)到檢驗(yàn)學(xué)習(xí)成果的目的linux介紹Linux是一種針對PC計(jì)算機(jī)和工作站的操作系統(tǒng),它具有像Windows和Mac那樣的功能齊全的圖形用戶界面(GUI,GraphicalUserInterface)。LinusTorvald和其它的遍布世界各地的編程人員共同開發(fā)的。作為一種操作系統(tǒng),它具有與Unix,Mac,Windows和WindowsNT同樣的功能。

提到Linux我們不能不提GNU和Unix。RichardM.Stallman建立的自由軟件聯(lián)盟出版了兩種許可證,GNU通用公共許可證(GNUGneralPublicLicense,GPL)和GNU函數(shù)庫通用公共許可證(GNULibraryGneralPublicLicense,LGPL)。大部分GNU工程的軟件和文檔是以GNU通用公共許可證發(fā)行的,但是有一些庫是以GNU函數(shù)庫通用公共許可證發(fā)行的。按照GNU通用公共許可證的規(guī)定,Linux的源代碼可以自由獲取,這滿足了我們學(xué)習(xí)該系統(tǒng)的強(qiáng)烈愿望。GPL充分體現(xiàn)了Stallman的思想:只要用戶所做的修改是同等自由的,用戶可以自由地使用、拷貝、查詢、重用、修改甚至發(fā)布這個(gè)軟件。通過這種方式,GPL保證了Linux(以及同一許可證下的大量其他軟件)不僅現(xiàn)在自由可用,而且皮后經(jīng)過任何修改這后都仍然可以自由使用。

Unix是由AT—T貝爾實(shí)驗(yàn)室的KenThompson和DennisRitchie于1969年在一臺(tái)已經(jīng)廢棄了的PDP-7上開發(fā)的;最初它是一個(gè)用匯編語言寫成的單用戶操作系統(tǒng)。后來,他們又在PDP-11上用C語言重新編寫(發(fā)明C語言的部分目的就在于此),把Unix做成為了一個(gè)文本處理系統(tǒng),這使Unix在貝爾實(shí)驗(yàn)室得到廣泛的應(yīng)用。Unix的最初版本免費(fèi)提供給許多知名的大學(xué)的計(jì)算機(jī)系使用。加州大學(xué)伯克利分校的計(jì)算機(jī)系就是其中的一名,并地Unix進(jìn)行了修改增加了許多新的特點(diǎn),這就是主為人知的BSC版本的Unix。與此同時(shí),其它獨(dú)立開發(fā)的Unix版本也開始萌生。Unix不斷發(fā)展了,各種版本被應(yīng)用到不同的計(jì)算機(jī)使用。而Linux最初是專門為基于Intel的個(gè)人計(jì)算機(jī)設(shè)計(jì)的。

(1)Linux的昨天

1991年,一名叫LinusTorvalds的芬蘭大學(xué)生對Unix各種版本對于80386類的機(jī)器的脆弱支持十分不滿,他決定要開發(fā)出一個(gè)全功能的、支持POSIX標(biāo)準(zhǔn)的、類Unix的操作系統(tǒng)內(nèi)核,該系統(tǒng)吸收了BSD和SystemV的優(yōu)點(diǎn),同進(jìn)摒棄了它們的缺點(diǎn)。他獨(dú)立把這個(gè)內(nèi)核開發(fā)到0.02版,這個(gè)版本已經(jīng)可以運(yùn)行g(shù)cc、bash和很少的一些應(yīng)用程序。后來,他又開始了在因特網(wǎng)上尋求廣泛的幫助。

1994年,Linux已經(jīng)升級(jí)到1.0版本。它的源代碼量也呈指數(shù)形式增長,實(shí)現(xiàn)了基本的TCP/IP功能,此時(shí)Linux已經(jīng)擁有大約10萬的用戶。

(2)Linux的今天

作為一各服務(wù)器級(jí)的操作系統(tǒng),Linux已經(jīng)成熟了?,F(xiàn)在的Linux內(nèi)核由150多行代碼組成,能作為Web服務(wù)器平臺(tái),也為越來越多的商業(yè)用戶提供文件和打印服務(wù)。它既被當(dāng)作郵件服務(wù)器的一種候選平臺(tái),也被當(dāng)作一種強(qiáng)壯而安全的防火墻。

Linux的企業(yè)級(jí)特性,比如支持多處理器、支持大型文件系統(tǒng)、日志文件系統(tǒng)以及密集型計(jì)算和高可用性集群技術(shù),也逐步成熟。

桌面上的Linux也在繼續(xù)完善。KDE桌面提供的圖形用戶界面在易用性和可配置方面都能和微軟的Windows相媲美。

(3)Linux的明天

Linux最強(qiáng)大的生命力在于其公開的開發(fā)過程。每個(gè)人都有可以自由獲取內(nèi)核源程序,每個(gè)人都有要不得以運(yùn)載源程序加以修改,而后他人也可以自由獲取你修改后的源程序。Linux這種獨(dú)特的自由流暢的開發(fā)模型已被命名為bazaar(集市模型)。Bazaar開發(fā)模型通過重視實(shí)驗(yàn),征集并充分利用早期的反饋,對巨大數(shù)量的腦力資源進(jìn)行平衡配置,可以開發(fā)出更優(yōu)秀的軟件。本聯(lián)盟就是想通過bazaar開發(fā)模型,在網(wǎng)上召集一些Linux的愛好者,開發(fā)出更優(yōu)秀的操作系統(tǒng)或軟件。2技術(shù)說明2.1TCP和UDP通信的概念2.1.1UDP通信UDP是用戶數(shù)據(jù)報(bào)協(xié)議的簡稱。它是以中午連接的邏輯通信信道。UDP在傳送數(shù)據(jù)之前不需要先建立連接,遠(yuǎn)地主機(jī)的傳輸層在收到udp數(shù)據(jù)報(bào)后,不需要給出任何確認(rèn),所以不能保證其交付時(shí)可靠。它的特點(diǎn)是:因無連接,故提供的是不可靠的信道,但也是因無連接而具有很好的傳輸效率。2.1.2TCP通信TCP是傳輸控制協(xié)議的簡稱,它是提供一條全雙工的、可靠的信道。TCP提供面向連接的服務(wù),在傳送數(shù)據(jù)之前必須先建立連接,數(shù)據(jù)傳送結(jié)束后要釋放連接。TCP不提供廣播和多播服務(wù)。由于TCP要提供可靠的、面向連接的運(yùn)輸服務(wù),所以不可避免地增加了許多系統(tǒng)開銷,比如確認(rèn)、流量控制、計(jì)時(shí)器以及連接管理等都需要占用許多系統(tǒng)的時(shí)空資源。兩個(gè)計(jì)算機(jī)之間如果使用TCP通信,其連接過程需要三次握手實(shí)現(xiàn),如實(shí)驗(yàn)圖1-1所示。圖1-1用三次握手建立TCP連接對于兩個(gè)計(jì)算機(jī)之間連接的釋放過程也需要類似的3次握手的互相確認(rèn)的過程,如實(shí)驗(yàn)圖1-2所示。圖1-2TCP連接的釋放過程2.2客戶/服務(wù)器模型在客戶/服務(wù)器模型中,多個(gè)相互通信的計(jì)算機(jī)都作為客戶端,與網(wǎng)絡(luò)服務(wù)器進(jìn)行連接,并通過服務(wù)器進(jìn)行信息的傳遞。所以多個(gè)客戶端之間的通信就變?yōu)榱丝蛻舳伺c服務(wù)端的通信。所以,采用客戶/服務(wù)器模型進(jìn)行網(wǎng)絡(luò)聊天需要分別編寫服務(wù)器端和客戶端的程序,服務(wù)器和客戶端之間相互通信的同步關(guān)系和各自的程序流程如實(shí)驗(yàn)圖1-3所示。圖1-3Socket通信流程圖2.3網(wǎng)絡(luò)套接字(socket)的概念1介紹上世紀(jì)中后期,在美國國防部高研署(DARPA)將TCP/IP的軟件提供給加利尼亞大學(xué)Berkeley分校后,TCP/IP很快被集成到Unix中,同時(shí)出現(xiàn)了許多成熟的TCP/IP應(yīng)用程序接口(API)。這個(gè)API稱為Socket接口(套接口)。Socket在計(jì)算機(jī)中提供了一個(gè)通信端口,可以通過這個(gè)端口與任何一個(gè)具有Socket接口的計(jì)算機(jī)通信。應(yīng)用程序在網(wǎng)絡(luò)上傳輸,接收的信息都通過這個(gè)Socket接口來實(shí)現(xiàn)。在應(yīng)用開發(fā)中就像使用文件句柄一樣,可以對Socket句柄進(jìn)行讀、寫操作。今天,Socket接口是TCP/IP網(wǎng)絡(luò)最為通用的API,也是在Internet上進(jìn)行應(yīng)用開發(fā)最為通用的API。Linux操作系統(tǒng)具有良好的穩(wěn)定性和出色的網(wǎng)絡(luò)性能,因此被廣泛應(yīng)用于網(wǎng)絡(luò)服務(wù)領(lǐng)域。而在Linux下開發(fā)高性能的網(wǎng)絡(luò)通信程序,是充分發(fā)揮Linux網(wǎng)絡(luò)特性的一個(gè)關(guān)鍵因素。2Socket原理簡介當(dāng)用電話與他人通信時(shí),必須拿起話筒,撥叫對方的電話號(hào)碼,然后等待對方的應(yīng)答。當(dāng)雙方進(jìn)行通話的時(shí)候,就建立了一個(gè)具有兩個(gè)端點(diǎn)的通信線路,這兩個(gè)端點(diǎn)是:本地的電話號(hào)碼(在本地位置)。對方的電話號(hào)碼(在對方的位置處)。雙方的通信與通信的兩個(gè)端點(diǎn)和他們之間的通信線路有關(guān)。Linux中的套接口與電話非常相似。套接口代表通信線路中的端點(diǎn),兩端點(diǎn)之間就是數(shù)據(jù)通信網(wǎng)絡(luò)。套接口與電話的相似性還表現(xiàn)在另一方面。當(dāng)給某人打電話時(shí),撥叫的是對方用戶的電話號(hào)碼。而套接口中的網(wǎng)絡(luò)地址就相當(dāng)于電話號(hào)碼。通過在程序中指定遠(yuǎn)程套接口的地址,就可以建立從本地套接口到遠(yuǎn)端套接口的通信。TCP/IP是計(jì)算機(jī)互連最常使用的網(wǎng)絡(luò)通訊協(xié)議,TCP/IP的核心部分由網(wǎng)絡(luò)操作系統(tǒng)的內(nèi)核實(shí)現(xiàn),應(yīng)用程序通過編程接口來訪問TCP/IP。套接字(Socket)是介于網(wǎng)絡(luò)應(yīng)用層和傳輸層之間的編程接口,套接字接口提供了訪問下層通信協(xié)議的大量系統(tǒng)調(diào)用和相應(yīng)的數(shù)據(jù)結(jié)構(gòu)。在Linux中,套接字接口是應(yīng)用程序訪問下層的網(wǎng)絡(luò)協(xié)議的惟一方法。具體講,套接字在用戶級(jí)實(shí)現(xiàn)了兩個(gè)應(yīng)用程序之間的網(wǎng)絡(luò)連接和數(shù)據(jù)交換,所以Linux中的套接字意味著網(wǎng)絡(luò)上的連接。套接字在TCP/IP網(wǎng)絡(luò)模型中的地位如圖1所示。Socket分為以下三種類型:流式套接字(StreamSocket):是最常用的套接字類型,文件傳送協(xié)議(FTP)即使用流式套接字。提供一個(gè)面向連接、可靠的數(shù)據(jù)傳輸服務(wù),數(shù)據(jù)無差錯(cuò)、無重復(fù)地發(fā)送,且按發(fā)送順序接收。內(nèi)設(shè)流量控制,避免數(shù)據(jù)流超限。數(shù)據(jù)被看作是字節(jié)流,無長度限制。數(shù)據(jù)報(bào)套接字(DatagramSocket):TCP/IP協(xié)議族中的UDP協(xié)議使用此類接口,它是無連接的服務(wù),數(shù)據(jù)通過相互獨(dú)立的報(bào)文進(jìn)行傳輸,提供了一個(gè)無連接服務(wù)。數(shù)據(jù)包以獨(dú)立包形式被發(fā)送,不提供無錯(cuò)保證,數(shù)據(jù)可能丟失或重復(fù),并且接收順序混亂。原始數(shù)據(jù)報(bào)套接字(RawSocket):該接口允許對較低層協(xié)議,如IP、ICMP直接訪問。常用于檢驗(yàn)新的協(xié)議實(shí)現(xiàn)或訪問。3Socket通信過程與程序開發(fā)3.1Socket通信過程基于TCP可靠連接的客戶與服務(wù)器連接進(jìn)程流程圖如圖2。Socket工作過程如下:服務(wù)器首先啟動(dòng),通過調(diào)用Socket(),建立一個(gè)Socket,然后調(diào)用bind()將該Socket和本地網(wǎng)絡(luò)地址綁系在一起,再調(diào)用listen()使Socket做好偵聽的準(zhǔn)備,并規(guī)定它的請求隊(duì)列的長度,之后就調(diào)用accept()來接收連接??蛻粼诮ocket后就可調(diào)用connect()和服務(wù)器建立連接。連接一旦建立,客戶機(jī)和服務(wù)器之間就可以通過調(diào)用send()和recv()來發(fā)送和接收數(shù)據(jù)。最后,待數(shù)據(jù)傳送結(jié)束后,雙方調(diào)用close()關(guān)閉Socket。3.2Socket通信程序開發(fā)下面詳細(xì)說明Socket通信程序的開發(fā)過程:(1)步驟1:建立套接口socket()intsockfd=socket(intdomain,inttype,intprotocol),其中domain參數(shù)指定socket協(xié)議族,包括PF_LOACL和PF_INET,PF_LOACL表示使用本地套接口,PF_INET表示使用Internet套接口。Type參數(shù)定義了套接口的類型,包括SOCK_STREAM和SOCK_DGRAM,SOCK_STREAM指定為流套接口,SOCK_DGRAM指定為數(shù)據(jù)報(bào)套接口。protocol通常賦值“0”,意味套接口使用TCP/IP協(xié)議。socket()調(diào)用返回一個(gè)整型socket描述符,可以在后面的調(diào)用使用它,當(dāng)其值為-1時(shí),說明有錯(cuò)誤發(fā)生。(2)步驟2:綁定套接口bind()當(dāng)用socket()建立套接口后,該套接口還是處于無名狀態(tài)的,無名套接口就象沒有號(hào)碼的電話一樣,別人無法向發(fā)送信息(在同一linux內(nèi)核下可實(shí)現(xiàn)無名狀態(tài)下通信)。為了像電話分配電話號(hào)碼一樣,可以通過bind()為建立的套接口綁定一個(gè)名字———分配地址。這一步對客戶端不是必需的。intbind(intsockfd,structsockaddr_my_addr,intaddrlen)。sockfd是一個(gè)socket描述符,my_addr是一個(gè)指圖計(jì)算機(jī)應(yīng)用向包含有本機(jī)IP地址及端口號(hào)等信息的sockaddr類型的指針。addrlen常被設(shè)置為sizeof(structockaddr),如果函數(shù)調(diào)用成功,就返回0,否則就返回為-1,我們可以通過查看errno的值來了解錯(cuò)誤的原因。需要指出的是,可以用下面的賦值實(shí)現(xiàn)自動(dòng)獲得本機(jī)IP地址和隨機(jī)獲取一個(gè)沒有被占用的端口號(hào):my_addr.sin_port=0。/<系統(tǒng)隨機(jī)選擇一個(gè)未被使用的端口號(hào)</my_addr.sin_addr.s_addr=INADDR_ANY。/<填入本機(jī)IP地址</通過將my_addr.sin_port置為0,函數(shù)會(huì)自動(dòng)為選擇一個(gè)未占用的端口來使用。同樣,通過將my_addr.sin_addr.s_addr置為INADDR_ANY,系統(tǒng)會(huì)自動(dòng)填入本機(jī)IP地址。bind()函數(shù)在成功被調(diào)用時(shí)返回0。遇到錯(cuò)誤時(shí)返回“-1”并將errno置為相應(yīng)的錯(cuò)誤號(hào)。另外要注意的是,當(dāng)調(diào)用函數(shù)時(shí),一般不要將端口號(hào)置為小于1024的值,因?yàn)?~1024是保留端口號(hào),可以使用大于1024中任何一個(gè)沒有被占用的端口號(hào)。(3)步驟3:請求連接connect()當(dāng)客戶端綁定地址后,發(fā)送請求連接信號(hào)connect()來與遠(yuǎn)端服務(wù)器建立一個(gè)TCP連接。connect()函數(shù)原型為:intconnect(intsockfd,structsockaddr<serv_addr,intaddrlen)。sockfd是目的服務(wù)器的socket描述符。serv_addr是包含目的機(jī)IP地址和端口號(hào)的指針,addrlen為結(jié)構(gòu)的大小。遇到錯(cuò)誤時(shí)返回-1,并且errno中包含相應(yīng)的錯(cuò)誤碼。進(jìn)行客戶端程序設(shè)計(jì)無須調(diào)用bind(),因?yàn)檫@種情況下只需知道目的機(jī)器的IP地址,而客戶通過哪個(gè)端口與服務(wù)器建立連接并不需要關(guān)心,內(nèi)核會(huì)自動(dòng)選擇一個(gè)未被占用的端口供客戶端來使用。(4)步驟4:監(jiān)聽連接listen()在服務(wù)器端程序中,當(dāng)socket與某一端口捆綁以后,就需要監(jiān)聽該端口,以便對到達(dá)的服務(wù)請求加以處理。intlisten(intsockfd,intbacklog)。sockfd是Socket系統(tǒng)調(diào)用返回的socket描述符。backlog指定在請求隊(duì)列中允許的最大請求數(shù),進(jìn)入的連接請求將在隊(duì)列中等待accept()它們。backlog對隊(duì)列中等待服務(wù)的請求的數(shù)目進(jìn)行了限制,對于小型服務(wù)器,隊(duì)列長度應(yīng)該為5或是稍大一些的值,而對于網(wǎng)站服務(wù)器,我們就需要更大的值,比如說16或是更大。當(dāng)listen遇到錯(cuò)誤時(shí)返回-1,errno被置為相應(yīng)的錯(cuò)誤碼。(5)步驟5:連接端口的服務(wù)請求當(dāng)某個(gè)客戶端試圖與服務(wù)器監(jiān)聽的端口連接時(shí),該連接請求將排隊(duì)等待服務(wù)器accept()它。通過調(diào)用accept()函數(shù)為其建立一個(gè)連接,accept()函數(shù)將返回一個(gè)新的socket描述符,來供這個(gè)新連接來使用。而服務(wù)器可以繼續(xù)在以前的那個(gè)socket上監(jiān)聽,同時(shí)可以在新的socket描述符上進(jìn)行數(shù)據(jù)send()(發(fā)送)和recv()(接收)操作。intaccept(intsockfd,void<addr,int<addrlen)。sockfd是被監(jiān)聽的socket描述符,addr通常是一個(gè)指向sockaddr_in變量的指針,該變量用來存放提出連接請求服務(wù)的主機(jī)的信息(某臺(tái)主機(jī)從某個(gè)端口發(fā)出該請求)。addrlen通常為一個(gè)指向值為sizeof(structsockaddr_in)的整型指針變量。錯(cuò)誤發(fā)生時(shí)返回一個(gè)-1并且設(shè)置相應(yīng)的errno值。accept()之前,通常將addrlen初始化為0。(6)步驟6:數(shù)據(jù)傳輸send()和recv()send()和recv()這兩個(gè)函數(shù)是用于面向連接的socket上進(jìn)行數(shù)據(jù)傳輸。send()函數(shù)原型為:intsend(intsockfd,constvoid<msg,intlen,intflags)。sockfd是想用來傳輸數(shù)據(jù)的socket描述符,msg是一個(gè)指向要發(fā)送數(shù)據(jù)(可以是字符型、整型、浮點(diǎn)型等)的指針。len是以字節(jié)為單位的數(shù)據(jù)的長度。flags一般情況下置為0。send()函數(shù)返回實(shí)際上發(fā)送出的字節(jié)數(shù),可能會(huì)少于希望發(fā)送的數(shù)據(jù)。所以需要對send()的返回值進(jìn)行測量。當(dāng)send()返回值與len不匹配時(shí),應(yīng)該對這種情況進(jìn)行處理。recv()函數(shù)原型為:intrecv(intsockfd,void<buf,intlen,unsignedintflags)。sockfd是接收數(shù)據(jù)的socket描述符。buf是存放接收數(shù)據(jù)的緩沖區(qū)。len是緩沖的長度。flags也被置為0。recv()返回實(shí)際上接收的字節(jié)數(shù),或當(dāng)出現(xiàn)錯(cuò)誤時(shí),返回-1并置相應(yīng)的errno值。(7)步驟7:關(guān)閉連接close()當(dāng)所有的數(shù)據(jù)操作結(jié)束以后,可以調(diào)用close()函數(shù)來釋放該socket,從而停止在該socket上的任何數(shù)據(jù)操作。摘要:在Linux下開發(fā)高性能的網(wǎng)絡(luò)通信程序,是充分發(fā)揮Linux網(wǎng)絡(luò)特性的一個(gè)關(guān)鍵因素。Socket接口是TCP/IP網(wǎng)絡(luò)最為通用的API,Socket在計(jì)算機(jī)中提供了一個(gè)通信端口,可以通過這個(gè)端口與任何一個(gè)具有Socket接口的計(jì)算機(jī)通信。Socket接口上TCP/IP網(wǎng)絡(luò)應(yīng)用程序接口(API),它提供了許多函數(shù)和例程,程序員可以使用它們來開發(fā)TCP/IP網(wǎng)絡(luò)應(yīng)用程序。2Socket使用Socket接口進(jìn)行網(wǎng)絡(luò)通信的過程如圖1-3所示,簡要步驟如下:建立一個(gè)Socket.按要求配置socket,將socket連接到遠(yuǎn)程主機(jī)或給socket指定以各本地協(xié)議端口。按要求通過socket發(fā)送和接受數(shù)據(jù)。關(guān)閉此socket。這是通過Socket實(shí)現(xiàn)點(diǎn)對點(diǎn)通信需要掌握的4個(gè)編程要點(diǎn)。2.4多線程的概念上述點(diǎn)對點(diǎn)通信的實(shí)現(xiàn)知識(shí)完成了主機(jī)進(jìn)程與服務(wù)器進(jìn)程之間的連接,建立連接的進(jìn)程之間是一對一的聯(lián)系,即主機(jī)的一個(gè)進(jìn)程與服務(wù)器的一個(gè)進(jìn)程之間建立的連接。而每個(gè)進(jìn)程進(jìn)行通信的環(huán)節(jié)都包括了發(fā)送信息和接口信息兩個(gè)任務(wù),這兩個(gè)任務(wù)通過一個(gè)端口地址發(fā)送和接收。對于多個(gè)并發(fā)的任務(wù)需要?jiǎng)?chuàng)建多個(gè)線程或線程去實(shí)現(xiàn)。使用一個(gè)進(jìn)程去完成發(fā)送信息是沒有問題的,因?yàn)榘l(fā)送總是主動(dòng)的;而使用同一個(gè)進(jìn)程再去完成接受信息去不一定會(huì)成功,因?yàn)榻邮苄畔⑹潜粍?dòng)的,所以當(dāng)沒有信息可以接收時(shí),該進(jìn)程就會(huì)被阻塞,從而導(dǎo)致發(fā)送任務(wù)也一起被阻塞。同一個(gè)端口的發(fā)送和接收是兩個(gè)并發(fā)任務(wù),應(yīng)該由兩個(gè)不同的任務(wù)去分別完成信息的發(fā)送和接收。這樣,當(dāng)接收信息任務(wù)因沒有信息而被阻塞時(shí),不至于影響發(fā)送任務(wù)的執(zhí)行。那么,發(fā)送和接收兩個(gè)任務(wù)是使用兩個(gè)進(jìn)程還是兩個(gè)進(jìn)程去完成呢?在網(wǎng)絡(luò)通信中,端口地址是以進(jìn)程為單位進(jìn)程分配的,而一個(gè)進(jìn)程與外界的消息發(fā)送與接收必須通過分配給它的同一個(gè)端口進(jìn)行。因此,不能通過創(chuàng)建進(jìn)程方式來解決上訴問題,因?yàn)閮蓚€(gè)進(jìn)程會(huì)分別對應(yīng)兩個(gè)不同的端口,而發(fā)送和接收必須使用同一端口。線程不是資源分配的單位,所以如果使用兩個(gè)線程不會(huì)對線程分配新的端口。因此,本實(shí)驗(yàn)需要使用兩個(gè)線程去分別完成發(fā)送和接收信息的任務(wù),這兩個(gè)線程共享其進(jìn)程擁有的統(tǒng)一個(gè)端口地址。由于創(chuàng)建進(jìn)程的進(jìn)程本身會(huì)作為一個(gè)線程來調(diào)度,所以只需要再創(chuàng)建一個(gè)線程專門負(fù)責(zé)接收信息就可以了。因此,對于從每個(gè)客戶端發(fā)來的請求,服務(wù)器端都要?jiǎng)?chuàng)建相應(yīng)的線程去接收并處理;同理,對于客戶端而言,也要?jiǎng)?chuàng)建一個(gè)線程去讀取服務(wù)器端發(fā)來的信息。3系統(tǒng)實(shí)現(xiàn)3.1Linux提供的有關(guān)Socket的系統(tǒng)調(diào)用Socket()作用:socket函數(shù)為客戶機(jī)或服務(wù)器創(chuàng)建一個(gè)sokcet格式:intsocket(intfamily,inttype,intprotocol)。 參數(shù)說明:Family:表示地址族,可以去AF_UNLX和AF_INT。其中,AF_UNLX只能夠用于單一的UNIX系統(tǒng)進(jìn)程間通信。AF_INT是針對Internet的,因而可以允許在遠(yuǎn)程主機(jī)之間通信,實(shí)驗(yàn)中使用AF_INT。Type:網(wǎng)絡(luò)程序所采用的通信協(xié)議,可以取SOCK_STREAM或SOCK_DGRAM。其中,SOCK_STREAM表明使用的是TCP協(xié)議,這樣提供按順序的、可靠的、雙向、面向連接的比特流;SOCKE_DGRAM表明使用的是UDP協(xié)議,這樣只會(huì)提供定長、不可靠、無連接的通信。bind()格式:intbind(intsockfd,structsockaddr*addr,intaddrlen)。參數(shù)說明:Sockfd:socket的文件描述符號(hào)。Sockaddr:表示名字所用的一個(gè)數(shù)據(jù)結(jié)構(gòu),用來保存地址(包括IP地址和端口)Addrlen:設(shè)置結(jié)構(gòu)大小長度。listen()格式:intlisten(intsockfd,intbacklog)。作用:監(jiān)聽連接信號(hào),和accepted函數(shù)合同。參數(shù)說明:Sockfd:表示socket調(diào)用返回的文件描述符。Backlog:表示接入隊(duì)列允許的連接數(shù)目,大多數(shù)系統(tǒng)允許20個(gè),也可以子定義5~10個(gè)。accept()格式:Intaccept(intsockfd,void*addr,int*addrlen)。作用:與listen函數(shù)合用,監(jiān)聽信息、接收客戶端請求。參數(shù)說明:Sockfd:表示socket的文件描述符。Addr:表示指向局部的數(shù)據(jù)結(jié)構(gòu)structsockaddr-in的指針。Addrlen:表示地址的長度。connect()格式:intconnect(intsockfd,structsockaddr*serv_addr,intaddrlen)。作用:在面向連接的系統(tǒng)中客戶及連接服務(wù)器時(shí)使用,connect必須在bind后使用。參數(shù)作用:Sockfd:表示socket的文件描述符。Serv-addr:表示村訪目的端口和ip地址(套接字)的數(shù)據(jù)結(jié)構(gòu)。send()和recv()格式1:Intsend(intsockfd,constvod*msg,intlen,intflags)。功能:發(fā)送信息。格式2:Intrecv(intsockfd,void*buf,intlen,usignedintflags)。作用:用于流式socket、數(shù)據(jù)報(bào)socket內(nèi)部之間的通信。close()和shutdown()格式:Close(intsockfd)或Intshutdown(intsockfd,inthow)。參數(shù)說明:How的值為下面一種:0----不允許繼續(xù)接收;1----不允許繼續(xù)發(fā)送;2---不允許繼續(xù)發(fā)送和接收。有關(guān)線程的系統(tǒng)調(diào)用函數(shù)pthread_create()、pthread_join()3.2實(shí)驗(yàn)過程說明(使用TCP/IP)監(jiān)聽連接利用socket、bind、listen建立連接,步驟是:先用socket函數(shù)初始化socket,創(chuàng)建新的sockfd。Sockfd=socket(AF_INT,SOCK_STREAM,0)此步驟涉及到IP地址及其處理過程。參數(shù)說明:inet_addr函數(shù)INADDR_ANY該函數(shù)把由小數(shù)點(diǎn)分開的十進(jìn)制IP地址轉(zhuǎn)為unsingedlong類型,而在實(shí)驗(yàn)中所使用的為INADDR_ANY,使用利用自已的IP地址自動(dòng)填充。利用bind函數(shù)綁定端口和IP地址。My_addr.sin_family=AF_INET。/*將地址族類型設(shè)定好*/My_addr.sin_port=htons(MYPORT。/*將端口給其賦值*/My_addr.sin_addr.s_addr=INADDR_ANY。/*用連接地址自動(dòng)填充ip*/Bind(sockfd,(stuctsockaddr*)&my_addr,sizeof(stuctsockaddr))。/*sockfd是分配的socket名字,my-addr則便是分配好的端口與IP,用bind綁定*/利用listen監(jiān)聽請求發(fā)送請求1)利用gethostbyname獲取主機(jī)信息。2)初始化socket端口。3)利用connect函數(shù)將自己的IP地址等信息發(fā)送到主機(jī),等待主機(jī)調(diào)用accept函數(shù)來接受請求。主機(jī)接收請求,進(jìn)行數(shù)據(jù)通信1)主機(jī)利用accept接收請求。2)創(chuàng)建子進(jìn)程,顯示歡迎信息;3)接收返回信息,顯示連接成功,并推出連接;4)關(guān)閉客戶端口socket;5)關(guān)閉服務(wù)端socket,結(jié)束子線程。3.3TCP通信實(shí)現(xiàn)服務(wù)端源程序清單如下,設(shè)文件名為server.c#include<stdio.h>#include<stdlib.h>#include<errno.h>#include<string.h>#include<sys/types.h>#include<netinet/in.h>#include<sys/socket.h>#include<sys/wait.h>#include<pthread.h>#defineMYPORT3490#defineBACKLOG10#defineMAXDATASIZE1024intsockfd,new_fd。pthread_taccthread,recthread。voidrecmessage(void){while(1){intnumbytes。charbuf[MAXDATASIZE]。if((numbytes=recv(new_fd,buf,MAXDATASIZE,0))==-1){perror("recv")。 exit(1)。}buf[numbytes]='\0'。if(strcmp(buf,"exit")==0){ printf("Clientisclosed\n")。 close(new_fd)。 close(sockfd)。 exit(1)。} printf("Client:%s\n",buf)。}}voidacceptconnect(void){structsockaddr_intheir_sin_size。sin_size=sizeof(structsockaddr_in)。if((new_fd=accept(sockfd,(structsockaddr*)&their_addr,&sin_size))==-1){perror("accept")。exit(1)。}printf("server:gotconnectionfrom%s\n",inet_ntoa(their_addr.sin_addr))。if((pthread_create(&recthread,NULL,(void*)recmessage,NULL))!=0){printf("Createthreaderror!\r\n")。exit(1)。}}intmain(void){structsockaddr_inmy_addr。if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1){perror("socket")。exit(1)。}my_addr.sin_family=AF_INET。my_addr.sin_port=htons(MYPORT)。my_addr.sin_addr.s_addr=INADDR_ANY。bzero(&(my_addr.sin_zero),8)。if(bind(sockfd,(structsockaddr*)&my_addr,sizeof(structsockaddr))==-1){perror("bind")。exit(1)。}if(listen(sockfd,BACKLOG)==-1){perror("listen")。exit(1)。}if((pthread_create(&accthread,NULL,(void*)acceptconnect,NULL))!=0){printf("Createthreaderror!\r\n")。exit(1)。}while(1){charmsg[MAXDATASIZE]。scanf("%s",msg)。if(send(new_fd,msg,strlen(msg),0)==-1){perror("send")。close(new_fd)。exit(1)。}if(strcmp(msg,"exit")==0){printf("Byebye!\n")。close(new_fd)。close(sockfd)。exit(1)。}}return0。}客戶端源程序清單如下,設(shè)文件名為client.c#include<stdio.h>#include<stdlib.h>#include<errno.h>#include<string.h>#include<netdb.h>#include<sys/types.h>#include<netinet/in.h>#include<sys/socket.h>#include<pthread.h>#definePORT3490#defineMAXDATASIZE1024intsockfd。pthread_trecthread。voidrecmessage(void){while(1){intnumbytes。charbuf[MAXDATASIZE]。if((numbytes=recv(sockfd,buf,MAXDATASIZE,0))==-1){perror("recv")。exit(1)。}buf[numbytes]='\0'。if(strcmp(buf,"exit")==0){printf("Serverisclosed\n")。close(sockfd)。exit(1)。}printf("Server:%s\n",buf)。}}intmain(intargc,char*argv[]){structhostent*he。structsockaddr_intheir_addr。if(argc!=2){fprintf(stderr,"usage:clienthostname\n")。exit(1)。}if((he=gethostbyname(argv[1]))==NULL){

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(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ǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論