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

下載本文檔

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

文檔簡(jiǎn)介

1、封面作者:PanHongliang僅供個(gè)人學(xué)習(xí)姓名: 方 建學(xué)號(hào): 109074359班級(jí):網(wǎng)絡(luò)工程 1031背景1.1開發(fā)背景在網(wǎng)絡(luò)無所不在的今天,在 Internet 上,有 ICQ、MSN、Gtalk、 OICQ 等網(wǎng)絡(luò)聊天軟件,極大程度上方便了處于在世界各地的友人之間的相互聯(lián) 系,也使世界好像一下子縮小了,不管你在哪里,只要你上了網(wǎng),打開這些 軟件,就可以給你的朋友發(fā)送信息,不管對(duì)方是否也同時(shí)在線,只要知道他 有號(hào)碼。Linux 操作系統(tǒng)作為一個(gè)開源的操作系統(tǒng)被越來越多的人所應(yīng)用,它的 好處在于操作系統(tǒng)源代碼的公開化!只要是基于 GNU 公約的軟件你都可以 任意使用并修改它的源代碼。但

2、對(duì)很多習(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í)成果的目的1.2linux介紹Linux 是一種針對(duì) PC 計(jì)算機(jī)和工作站的操作系統(tǒng),它具有像 Windows 和 Mac 那樣的功能齊全的 圖形用戶界面( GUI, G

3、raphical User Interface) 。 L i n u s Torvald 和其它的遍布世界各地的編程人員共同開發(fā)的。作為一種操作系統(tǒng) , 它 具 有 與Unix,Mac,Windows 和 Windows NT 同 樣 的 功 能 。提到 Linux 我們不能不提 GNU 和 Unix。Richard M.Stallman 建立的自由軟 件 聯(lián) 盟出 版 了 兩 種 許 可 證 ,GNU 通 用 公 共 許 可 證 (GNU Gneral Public License,GPL)和 GNU 函數(shù)庫(kù)通用公共許可證(GNU Library Gneral PublicLicense,L

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

5、 Dennis Ritchie 于 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ā)展了 ,各

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

7、升級(jí)到 1.0 版本。它的源代碼量也呈指數(shù)形式增長(zhǎng),實(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ù)完善。

8、KDE 桌面提供的圖形用戶界面在易用性和 可 配 置方 面 都 能 和 微 軟 的 Windows 相 媲 美 。 (3) Linux 的明天 Linux 最強(qiáng)大的生命力在于其公開的開發(fā)過程。每個(gè)人 都有可以自由獲取內(nèi)核源程序 ,每個(gè)人都有要不得以運(yùn)載源程序加以修改 ,而 后他人也可以自由獲取你修改后的源程序。 Linux 這種獨(dú)特的自由流暢的開 發(fā)模型已被命名為 bazaar (集市模型)。Bazaar 開發(fā)模型通過重視實(shí)驗(yàn),征集 并充分利用早期的反饋 ,對(duì)巨大數(shù)量的腦力資源進(jìn)行平衡配置 ,可以開發(fā)出更 優(yōu)秀的軟件。本聯(lián)盟就是想通過bazaar 開發(fā)模型,在網(wǎng)上召集一些Linux 的愛好者,

9、開發(fā)出更優(yōu)秀的操作系統(tǒng)或軟件。2技術(shù)說明2.1 TCP和UDP通信的概念2.1.1 UDP 通信UDP 是用戶數(shù)據(jù)報(bào)協(xié)議的簡(jiǎn)稱。它是以中午連接的邏輯通信信道。 UDP 在 傳送數(shù)據(jù)之前不需要先建立連接,遠(yuǎn)地主機(jī)的傳輸層在收到 udp 數(shù)據(jù)報(bào)后,不 需要給出任何確認(rèn),所以不能保證其交付時(shí)可靠。它的特點(diǎn)是:因無連接,故 提供的是不可靠的信道,但也是因無連接而具有很好的傳輸效率。2.1.2 TCP 通信TCP 是傳輸控制協(xié)議的簡(jiǎn)稱,它是提供一條全雙工的、可靠的信道。 TCP 提 供面向連接的服務(wù),在傳送數(shù)據(jù)之前必須先建立連接,數(shù)據(jù)傳送結(jié)束后要釋放 連接。TCP不提供廣播和多播服務(wù)。由于 TCP 要提

10、供可靠的、面向連接的運(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連接對(duì)于兩個(gè)計(jì)算機(jī)之間連接的釋放過程也需要類似的 3 次握手的互相確認(rèn)的 過程,如實(shí)驗(yàn)圖 1-2 所示。圖1-2 TCP連接的釋放過程2.2客戶/服務(wù)器模型在客戶/服務(wù)器模型中,多個(gè)相互通信的計(jì)算機(jī)都作為客戶端,與網(wǎng)絡(luò)服務(wù) 器進(jìn)行連接,并通過服務(wù)器進(jìn)行信息的傳遞。所以多個(gè)客戶端之間的通信就變 為了客戶端與服務(wù)端的通信。所以,采用客戶/服務(wù)器

11、模型進(jìn)行網(wǎng)絡(luò)聊天需要分別編寫服務(wù)器端和客戶端的程序,服務(wù)器和客戶端之間相互通信的同步關(guān)系 和各自的程序流程如實(shí)驗(yàn)圖 1-3 所示。圖1-3 Socket通信流程圖2.3網(wǎng)絡(luò)套接字(socket)的概念1介紹上世紀(jì)中后期,在美國(guó)國(guó)防部高研署(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 接口的

12、計(jì)算機(jī)通信。應(yīng)用程序在網(wǎng)絡(luò)上傳輸 , 接收的信息都 通過這個(gè) Socket 接口來實(shí)現(xiàn)。在應(yīng)用開發(fā)中就像使用文件句柄一樣 , 可以 對(duì) 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)鍵因素。2 Socket 原理簡(jiǎn)介當(dāng)用電話與他人通信時(shí) , 必須拿起話筒 , 撥叫對(duì)方的電話號(hào)碼 , 然后等 待

13、對(duì)方的應(yīng)答。 當(dāng)雙方進(jìn)行通話的時(shí)候 , 就建立了一個(gè)具有兩個(gè)端點(diǎn)的通 信線路 , 這兩個(gè)端點(diǎn)是 : 本地的電話號(hào)碼 ( 在本地位置 ) 。對(duì)方的電話號(hào)碼 ( 在對(duì)方的位置處 ) 。雙方的通信與通信的兩個(gè)端點(diǎn)和他們之間的通信線路 有關(guān)。 Linux 中的套接口與電話非常相似。套接口代表通信線路中的端點(diǎn) , 兩端點(diǎn)之間就是數(shù)據(jù)通信網(wǎng)絡(luò)。套接口與電話的相似性還表現(xiàn)在另一方面。 當(dāng)給某人打電話時(shí) , 撥叫的是對(duì)方用戶的電話號(hào)碼。而套接口中的網(wǎng)絡(luò)地址 就相當(dāng)于電話號(hào)碼。通過在程序中指定遠(yuǎn)程套接口的地址 , 就可以建立從本 地套接口到遠(yuǎn)端套接口的通信。 TCP /IP 是計(jì)算機(jī)互連最常使用的網(wǎng)絡(luò)通訊協(xié)議

14、, 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 分為以下三種類型 :流式套接字 ( Stream Socket) :是最常用的套接字類型 ,

15、文件傳送協(xié)議( FTP)即使用流式套接字。提供一個(gè)面向連接、可靠的數(shù)據(jù)傳輸服務(wù) , 數(shù) 據(jù)無差錯(cuò)、無重復(fù)地發(fā)送 , 且按發(fā)送順序接收。內(nèi)設(shè)流量控制 , 避免數(shù)據(jù)流超限。數(shù)據(jù)被看作是字節(jié)流,無長(zhǎng)度限制。數(shù)據(jù)報(bào)套接字(Datagram Socket) : 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)套接字(Raw Socket):該接口允許對(duì)較低層協(xié)議,如 IP、ICMP 直接訪問。常用于檢驗(yàn)新的協(xié)議實(shí)現(xiàn)或訪問。3 Socke

16、t 通信過程與程序開發(fā)3.1 Socket 通信過程基于 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ī)定它的請(qǐng)求隊(duì)列的長(zhǎng)度,之后就調(diào) 用 accept()來接收連接??蛻粼诮?Socket 后就可調(diào)用 connect()和服務(wù)器 建立連接。連接一旦建立,客戶機(jī)和服務(wù)器之間就可以通過調(diào)用send()和recv()來發(fā)送和接收數(shù)據(jù)。最后,待數(shù)據(jù)傳送結(jié)束后,雙方調(diào)

17、用 close()關(guān) 閉 Socketo3.2 Socket 通信程序開發(fā)下面詳細(xì)說明 Socket 通信程序的開發(fā)過程:(1)步驟 1:建立套接口 socket()int sockfd = socket ( int doma in, int type, in tprotocol),其中 domain 參數(shù)指定 socket 協(xié)議族,包括 PF_LOACL 和 PF_INET, PF_LOACL 表示使用本地套接口,PF_INET 表示使用 In ternet套接口。 Type 參數(shù)定義 了套接口的類型,包括 SOCK_STREA 和 SOCK_DGRAM, SOCK_STR 指定為流 套接口

18、 ,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è)名字分配地址。這一步對(duì)客戶端不是必

19、需的。int bind ( int sockfd, struct sockaddr_my_addr,int addrlen)。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_por

20、t=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)?11024 是保留端口號(hào),可以

21、使用大于 1024 中任何一個(gè)沒有被占用的端口號(hào)。( 3) 步驟 3: 請(qǐng)求連接 connect() 當(dāng)客戶端綁定地址后 , 發(fā)送請(qǐng)求連接信號(hào) connect() 來與遠(yuǎn)端服務(wù) 器建立一個(gè) TCP 連接。connect() 函數(shù)原型為 :int connect ( int sockfd, 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)

22、行客戶端程序設(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)聽 該端口 , 以便對(duì)到達(dá)的服務(wù)請(qǐng)求加以處理。int listen( int sockfd, int backlog)。 sockfd 是 Socket 系統(tǒng)調(diào)用返回的 socket 描述符。 backlog 指定在請(qǐng)求隊(duì)列中允許的最大請(qǐng)求數(shù) , 進(jìn)入 的連接請(qǐng)求將在隊(duì)列中等待

23、accept() 它們。 backlog 對(duì)隊(duì)列中等待服務(wù)的請(qǐng) 求的數(shù)目進(jìn)行了限制 , 對(duì)于小型服務(wù)器 , 隊(duì)列長(zhǎng)度應(yīng)該為 5 或是稍大一些的 值 , 而對(duì)于網(wǎng)站服務(wù)器 ,我們就需要更大的值 , 比如說 16 或是更大。當(dāng) listen 遇到錯(cuò)誤時(shí)返回 - 1, errno 被置為相應(yīng)的錯(cuò)誤碼。( 5) 步驟 5: 連接端口的服務(wù)請(qǐng)求 當(dāng)某個(gè)客戶端試圖與服務(wù)器監(jiān)聽的端口連接時(shí) , 該連接請(qǐng)求將排隊(duì)等待服務(wù)器 accept()它。通過調(diào)用 accept()函數(shù)為其建立一個(gè)連接,accept。函數(shù) 將返回一個(gè)新的 socket 描述符 , 來供這個(gè)新連接來使用。而服務(wù)器可以繼 續(xù)在以前的那個(gè)soc

24、ket 上監(jiān)聽 , 同時(shí)可以在新的 socket 描述符上進(jìn)行數(shù)據(jù)send ()( 發(fā)送)和 recv()( 接收)操作int accept( int sockfd, voidaddr, int addrlen) 。sockfd 是被監(jiān)聽的 socket 描述符 , addr 通常是一個(gè)指向 sockaddr_in 變 量的指針 ,該變量用來存放提出連接請(qǐng)求服務(wù)的主機(jī)的信息 ( 某臺(tái)主機(jī)從某 個(gè)端口發(fā)出該請(qǐng)求 ) 。addrlen 通常為一個(gè)指向值為 sizeof ( struct sockaddr_in) 的整型指針變量。錯(cuò)誤發(fā)生時(shí)返回一個(gè) - 1 并且設(shè)置相應(yīng)的 errno 值。accep

25、t。之前,通常將 addrlen 初始化為 0。(6) 步驟 6:數(shù)據(jù)傳輸 send()和 recv()send()和 recv()這兩個(gè)函數(shù)是用于面向連接的 socket 上進(jìn)行數(shù)據(jù)傳輸。send() 函數(shù)原型為 :int send ( int sockfd, const voidmsg, int len, intflags)。sockfd 是想用來傳輸數(shù)據(jù)的 socket 描述符 , msg 是一個(gè)指向要發(fā)送數(shù)據(jù)( 可以是字符型、整型、浮點(diǎn)型等 ) 的指針。 len 是以字節(jié)為單位的數(shù)據(jù)的 長(zhǎng)度。 flags一般情況下置為 0。send() 函數(shù)返回實(shí)際上發(fā)送出的字節(jié)數(shù) , 可能會(huì)少于希望

26、發(fā)送的數(shù)據(jù)。所 以需要對(duì)send() 的返回值進(jìn)行測(cè)量。當(dāng) send() 返回值與 len 不匹配時(shí) , 應(yīng)該 對(duì)這種情況進(jìn)行處理。recv() 函數(shù)原型為 :int recv ( int sockfd, voidbuf, int len, unsignedint flags)。sockfd 是接收數(shù)據(jù)的 socket 描述符。 buf 是存放接收數(shù)據(jù)的緩沖區(qū)。len 是緩沖的長(zhǎng)度。 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)

27、用 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)用程序。2 Socket使用 Socket 接口進(jìn)行網(wǎng)絡(luò)通信的過程如圖 1-3 所示,

28、簡(jiǎn)要步驟如下:(1) 建立一個(gè) Socket.(2) 按要求配置 socket,將 socket 連接到遠(yuǎn)程主機(jī)或給 socket 指定以各本地 協(xié)議端口。(3) 按要求通過 socket 發(fā)送和接受數(shù)據(jù)。(4) 關(guān)閉此 socket。這是通過 Socket 實(shí)現(xiàn)點(diǎn)對(duì)點(diǎn)通信需要掌握的 4 個(gè)編程要點(diǎn)。2.4多線程的概念上述點(diǎn)對(duì)點(diǎn)通信的實(shí)現(xiàn)知識(shí)完成了主機(jī)進(jìn)程與服務(wù)器進(jìn)程之間的連接,建 立連接的進(jìn)程之間是一對(duì)一的聯(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ā)送和接收。對(duì)于多個(gè)并發(fā)的任務(wù)需要?jiǎng)?chuàng)建多個(gè)

29、線程或線程去實(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)程方式來解決

30、上訴問題,因?yàn)閮蓚€(gè)進(jìn)程會(huì)分別對(duì)應(yīng)兩個(gè)不同的端口,而發(fā)送 和接收必須使用同一端口。線程不是資源分配的單位,所以如果使用兩個(gè)線程 不會(huì)對(duì)線程分配新的端口。因此,本實(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é)接 收信息就可以了。因此,對(duì)于從每個(gè)客戶端發(fā)來的請(qǐng)求,服務(wù)器端都要?jiǎng)?chuàng)建相應(yīng)的線程去接 收并處理;同理,對(duì)于客戶端而言,也要?jiǎng)?chuàng)建一個(gè)線程去讀取服務(wù)器端發(fā)來的 信息。3系統(tǒng)實(shí)現(xiàn)3.1 Linux提供的有關(guān)Socket的系統(tǒng)調(diào)用(1) Socket()作用:socket 函

31、數(shù)為客戶機(jī)或服務(wù)器創(chuàng)建一個(gè) sokcet格式:int socket(int family,int type,int protocol) 。參數(shù)說明:Family :表示地址族,可以去 AF_UNLX 和 AF_INT 。其中, AF_UNLX 只能夠用于單一的 UNIX 系統(tǒng)進(jìn)程間通信。 AF_INT 是針 對(duì) Internet 的,因而可以允許在遠(yuǎn)程主機(jī)之間通信,實(shí)驗(yàn)中使用AF_INT。Type : 網(wǎng) 絡(luò) 程 序 所 采 用 的 通 信 協(xié) 議 , 可 以 取 SOCK_STREAM 或SOCK_DGRAM。其中,SOCK_STREAM 表明使用的是 TCP 協(xié)議,這樣提供按 順序的、可靠

32、的、雙向、面向連接的比特流; SOCKE_DGRAM 表明使用的是 UDP 協(xié)議,這樣只會(huì)提供定長(zhǎng)、不可靠、無連接的通信。(2) bind( )格式:int bind(int sockfd,struct sockaddr *addr,int addrlen)。參數(shù)說明:Sockfd: socket 的文件描述符號(hào)。Sockaddr:表示名字所用的一個(gè)數(shù)據(jù)結(jié)構(gòu),用來保存地址(包括 IP 地址和端口)Addrle n:設(shè)置結(jié)構(gòu)大小長(zhǎng)度。(3) listen()格式:int listen(int sockfd, int backlog)。作用:監(jiān)聽連接信號(hào),和 accepted 函數(shù)合同。參數(shù)說明:

33、Sockfd:表示 socket 調(diào)用返回的文件描述符。Backlog :表示接入隊(duì)列允許的連接數(shù)目,大多數(shù)系統(tǒng)允許20 個(gè),也可以子定義 510 個(gè)。(4) accept()格式:Int accept (int sockfd, void *addr, int *addrlen)。作用:與 listen 函數(shù)合用,監(jiān)聽信息、接收客戶端請(qǐng)求。參數(shù)說明:Sockfd:表示 socket 的文件描述符。Addr :表示指向局部的數(shù)據(jù)結(jié)構(gòu) struct sockaddr-i n 的指針。Addrlen :表示地址的長(zhǎng)度。(5) connect()格式:int connect( int sockfd ,

34、 struct sockaddr *serv_addr , int addrlen。) 作用:在面向連接的系統(tǒng)中客戶及連接服務(wù)器時(shí)使用, connect 必須在 bind 后使用。參數(shù)作用:Sockfd :表示 socket 的文件描述符。Serv-addr:表示村訪目的端口和 ip 地址(套接字)的數(shù)據(jù)結(jié)構(gòu)。(6) send() 和 recv()格式 1 :Int send (int sockfd, const vod *msg,int len, int flags)。功能:發(fā)送信息。格式 2:Int recv (int sockfd , void *buf,int len, usigned

35、 int flags) 。作用:用于流式 socket、數(shù)據(jù)報(bào) socket 內(nèi)部之間的通信。(7) close() 和 shutdown()格式:Close( int sockfd)或Int shutdown(int sockfd , int how)。參數(shù)說明:How 的值為下面一種:0- 不允許繼續(xù)接收;1- 不允許繼續(xù)發(fā)送;2- 不允許繼續(xù)發(fā)送和接收。(8) 有關(guān)線程的系統(tǒng)調(diào)用函數(shù) pthread_create(、) pthread_join()3.2實(shí)驗(yàn)過程說明(使用TCP/IP)(1) 監(jiān)聽連接利用 socket、 bind、 listen 建立連接,步驟是:1)先用 socket

36、 函數(shù)初始化 socket,創(chuàng)建新的 sockfd。Sockfd = socket(AF_INT ,SOCK_STREAM,0 )2) 此步驟涉及到 IP 地址及其處理過程。參數(shù)說明:inet_addr 函數(shù) INADDR_ANY該函數(shù)把由小數(shù)點(diǎn)分開的十進(jìn)制 IP 地址轉(zhuǎn)為 unsinged long 類型,而在實(shí)驗(yàn) 中所使用的為 INADDR_ANY ,使用利用自已的 IP 地址自動(dòng)填充。a) 利用 bind 函數(shù)綁定端口和 IP 地址。My_addr.sin_family=AF_INET 。/*將地址族類型設(shè)定好 */My_addr.sin_port=htons(MYPORT。/* 將端口

37、給其賦值 */My_addr.sin_addr.s_addr=INADDR_ANY 。 /*用連接地址自動(dòng)填充 ip*/Bind(sockfd,(stuct sockaddr*)&my_addr,sizeof(stuct sockaddr)。/*sockfd 是分配的 socket 名字,my-addr 則便是分配好的端口與IP,用bind 綁定 */b) 利用 listen 監(jiān)聽請(qǐng)求(2) 發(fā)送請(qǐng)求1) 利用 gethostbyname 獲取主機(jī)信息。2) 初始化 socket 端口。3) 利用 connect 函數(shù)將自己的 IP 地址等信息發(fā)送到主機(jī),等待主機(jī)調(diào)用 accept函數(shù)

38、來接受請(qǐng)求。(3) 主機(jī)接收請(qǐng)求,進(jìn)行數(shù)據(jù)通信1) 主機(jī)利用 accept 接收請(qǐng)求。2) 創(chuàng)建子進(jìn)程,顯示歡迎信息;3) 接收返回信息,顯示連接成功,并推出連接;4) 關(guān)閉客戶端口 socket;5) 關(guān)閉服務(wù)端 socket,結(jié)束子線程。3.3 TCP通信實(shí)現(xiàn)(1) 服務(wù)端源程序清單如下,設(shè)文件名為server.c#include #include #include #include#include #include #include#include #include#define MYPORT 3490#define BACKLOG 10#define MAXDATASIZE 1024

39、int sockfd,new_fd 。pthread_t accthread,recthreadvoid recmessage(void) while(1)int numbytes。char bufMAXDATASIZE 。if(numbytes = recv(new_fd,buf,MAXDATASIZE,0) = -1) perror(recv)。exit(1) 。bufnumbytes = 0 。if(strcmp(buf,exit) = 0)printf(Client is closedn) 。close(new_fd)。close(sockfd)。exit(1)。printf(Clie

40、nt:%sn,buf) 。void acceptconnect(void)struct sockaddr_in their_ sin_size。sin_size = sizeof(struct sockaddr_in)。if(new_fd = accept(sockfd,(struct sockaddr*)&their_addr,&sin_size) =-1) perror(accept) 。exit(1) 。printf(server:got connection from %sn,inet_ntoa(their_addr.sin_addr)。if(pthre

41、ad_create(&recthread,NULL,(void *)recmessage,NULL)!=0) printf(Create thread error!rn) 。exit(1) 。int main(void)struct sockaddr_in my_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_add

42、r = INADDR_ANY 。 bzero(&(my_addr.sin_zero),8)。if(bind(sockfd,(struct sockaddr*)&my_addr,sizeof(struct sockaddr) =-1) perror(bind) 。exit(1) 。if(listen(sockfd,BACKLOG) = -1) perror(listen) 。exit(1) 。if(pthread_create(&accthread,NULL,(void *)acceptconnect,NULL) !=0) printf(Create thread err

43、or!rn) 。exit(1) 。while(1)char msgMAXDATASIZE 。 scanf(%s,msg)。if(send(new_fd,msg,strlen(msg),0)perror(send)。close(new_fd)。exit(1) 。if(strcmp(msg,exit) =0) printf(Byebye!n) 。close(new_fd)。 close(sockfd)。exit(1) 。return 0。(2) 客戶端源程序清單如下,設(shè)文件名為#include#include#include#include#include= -1)client.c#include

44、#include#include#include#define PORT 3490#define MAXDATASIZE 1024int sockfd 。pthread_t recthread。void recmessage(void)while(1)int numbytes。char bufMAXDATASIZE 。if(numbytes = recv(sockfd,buf,MAXDATASIZE,0) = -1) perror(recv) 。exit(1) 。bufnumbytes=0 。if(strcmp(buf,exit) = 0)printf(Server is closedn) 。

45、close(sockfd)。exit(1) 。printf(Server:%sn,buf) 。int main(int argc,char *argv)struct hostent *he。struct sockaddr_in their_addr。if(argc != 2)fprintf(stderr,usage:client hostnamen)。exit(1) 。if(he=gethostbyname(argv1) = NULL) herror(gethostbyname)。exit(1) 。if(sockfd = socket(AF_INET,SOCK_STREAM,0) = -1)

46、perror(socket) 。exit(1) 。their_addr.sin_family = AF_INET 。 their_addr.sin_port = htons(PORT。)their_addr.sin_addr = *(struct in_addr *)he-h_addr)。bzero(&(their_addr.sin_zero),8)。if(connect(sockfd,(struct sockaddr *)&their_addr,sizeof(struct sockaddr) = -1)perror(connect) 。exit(1) 。if(pthread_

47、create(&recthread,NULL,(void*)recmessage,NULL)!=0) printf(Create thread error!rn) 。exit(1) 。while(1)char msgMAXDATASIZE 。scanf(%s,msg)。 if(send(sockfd,msg,strlen(msg),0) = -1) perror(send)。close(sockfd)。exit(1) 。if(strcmp(msg,exit) = 0)printf(Byebye!n) 。close(sockfd)。exit(1) 。return 0。4運(yùn)行效果程序測(cè)試環(huán)

48、境:linux、unix、debian 等操作系統(tǒng)。測(cè)試軟件:putty、vmware 虛擬機(jī)(1)在編寫完 TCP 服務(wù)端程序 server.c 后,用 gcc Tpthread -o server.cserver 生成程序 server。在編寫完TCP客戶端程序client.c后, 用gcc Tpthread -o client.c client 生成程序 client(3) 在主機(jī)上打開一窗口,運(yùn)行 server。(4) 再打開另一個(gè)窗口或者在另一個(gè)主機(jī)上打開一個(gè)窗口,運(yùn)行client,輸入服務(wù)器的 IP 地址,并檢查器結(jié)果的正確性。輸入:【主】 # ./server【從】# ./client ( 為本機(jī)的 ip 地址)輸出:【主】 #server:got connection from (5) 客戶端、服務(wù)器端窗口之間以及交錯(cuò)發(fā)送信息的方

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(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ì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論