基于Linux網(wǎng)絡(luò)編程課程設(shè)計(jì)_第1頁(yè)
基于Linux網(wǎng)絡(luò)編程課程設(shè)計(jì)_第2頁(yè)
基于Linux網(wǎng)絡(luò)編程課程設(shè)計(jì)_第3頁(yè)
基于Linux網(wǎng)絡(luò)編程課程設(shè)計(jì)_第4頁(yè)
基于Linux網(wǎng)絡(luò)編程課程設(shè)計(jì)_第5頁(yè)
已閱讀5頁(yè),還剩29頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

1、2011級(jí)通信工程Linux網(wǎng)絡(luò)編程課程設(shè)計(jì)報(bào)告設(shè)計(jì)題目 基于Linux的網(wǎng)絡(luò)通信姓名及學(xué)號(hào) 羅文強(qiáng) 20110343005 楊潔 20110343006 何蕊 20110343007學(xué)院工程技術(shù)學(xué)院專業(yè)通信工程班級(jí)2011級(jí)3班指導(dǎo)教師 方飛2014年6月29日一、設(shè)計(jì)題目及要求1、設(shè)計(jì)題目 基于Linux的網(wǎng)絡(luò)通信2、 設(shè)計(jì)要求(1)、設(shè)計(jì)整個(gè)網(wǎng)絡(luò)系統(tǒng)的流程,并畫出流程圖。(2)、設(shè)計(jì)發(fā)送數(shù)據(jù)包的格式。(3)、學(xué)習(xí)linux環(huán)境下多進(jìn)程或多線程的編程方法。(4)、設(shè)計(jì)收發(fā)的模式、包括發(fā)送消息的內(nèi)容。(5)、設(shè)計(jì)多個(gè)客戶端傳送文件的方法。 指導(dǎo)教師簽名: 2014年 月 日二、指導(dǎo)教師評(píng)語(yǔ)

2、指導(dǎo)教師簽名: 2014 年 月 日三、成績(jī) 理論(60%): 分,作品(40%): 分,總分: 分。 驗(yàn)收蓋章 2014年 月 日 摘要  本課程設(shè)計(jì)實(shí)現(xiàn)了在linux下簡(jiǎn)單的網(wǎng)絡(luò)聊天室。在Linux下編寫并調(diào)試服務(wù)器端程序和客戶端程序,實(shí)現(xiàn)了客戶、服務(wù)器之間的連接和通信。可以在單機(jī)上開辟兩個(gè)窗口分別運(yùn)行客戶、服務(wù)器端的程序,或者將兩臺(tái)主機(jī)連接分別作為客戶和服務(wù)器的方式。本設(shè)計(jì)使用網(wǎng)絡(luò)套接字socket和多線程在網(wǎng)絡(luò)中的應(yīng)用,并基于linux下的vi編輯器。本方案經(jīng)gcc調(diào)試器調(diào)試成功,可以在單機(jī)網(wǎng)絡(luò)聊天中使用。關(guān)鍵詞:   linux

3、60;;socket ;vi  一、背景1.1 開發(fā)背景1.2 linux介紹二、實(shí)驗(yàn)?zāi)康娜?shí)驗(yàn)步驟3.1交叉編譯平臺(tái)的安裝四、設(shè)計(jì)原理4.1設(shè)計(jì)原理流程4.2程序流程分析五、網(wǎng)絡(luò)套接字(socket)的概念5.1 Socket 介紹5.2 Socket 原理簡(jiǎn)介5.3 Socket 通信過(guò)程與程序開發(fā)六、系統(tǒng)實(shí)現(xiàn)6.1 Linux提供的有關(guān)Socket的系統(tǒng)調(diào)用6.2 監(jiān)聽(tīng)連接6.3發(fā)送請(qǐng)求6.4主機(jī)接收請(qǐng)求,進(jìn)行數(shù)據(jù)通信七、 運(yùn)行效果一、背景1.1 開發(fā)背景 在網(wǎng)絡(luò)無(wú)所不在的今天,在Internet上,有ICQ、MSN、Gtalk、OICQ等網(wǎng)絡(luò)聊天軟件,極

4、大程度上方便了處于在世界各地的友人之間的相互聯(lián)系,也使世界好像一下子縮小了,不管你在哪里,只要你上了網(wǎng),打開這些軟件,就可以給你的朋友發(fā)送信息,不管對(duì)方是否也同時(shí)在線,只要知道他有號(hào)碼。 Linux 操作系統(tǒng)作為一個(gè)開源的操作系統(tǒng)被越來(lái)越多的人所應(yīng)用,它的好處在于操作系統(tǒng)源代碼的公開化!只要是基于GNU公約的軟件你都可以任意使用并修改它的源代碼。但對(duì)很多習(xí)慣于Windows操作系統(tǒng)的人來(lái)說(shuō),Linux的操作不夠人性化、交互界面不夠美觀,這給Linux操作系統(tǒng)的普及帶來(lái)了很大的阻礙。因此制作一個(gè)Linux 操作系統(tǒng)下的擁有人性化界面的實(shí)時(shí)通訊工具,將給那些剛剛接觸Linux操作系統(tǒng)的用戶帶來(lái)極大

5、的方便,而且通過(guò)設(shè)計(jì)這樣的一個(gè)應(yīng)用程序還能更好的學(xué)習(xí)網(wǎng)絡(luò)編程知識(shí)和掌握LINUX平臺(tái)上應(yīng)用程序設(shè)計(jì)開發(fā)的過(guò)程,將大學(xué)四年所學(xué)知識(shí)綜合運(yùn)用,以達(dá)到檢驗(yàn)學(xué)習(xí)成果的目的。1.2 linux介紹 Linux是一種針對(duì)PC計(jì)算機(jī)和工作站的操作系統(tǒng),它具有像Windows和Mac那樣的功能齊全的圖形用戶界面(GUI,Graphical User Interface)。Linus Torvald和其它的遍布世界各地的編程人員共同開發(fā)的。作為一種操作系統(tǒng),它具有與Unix,Mac,Windows和Windows NT同樣的功能。 提到Linux我們不能不提GNU和Unix。Richard M.Stallman

6、建立的自由軟件聯(lián)盟出版了兩種許可證,GNU通用公共許可證(GNU Gneral Public License,GPL)和GNU函數(shù)庫(kù)通用公共許可證(GNU Library Gneral Public License,LGPL)。大部分GNU工程的軟件和文檔是以GNU通用公共許可證發(fā)行的,但是有一些庫(kù)是以GNU函數(shù)庫(kù)通用公共許可證發(fā)行的。按照GNU通用公共許可證的規(guī)定,Linux的源代碼可以自由獲取,這滿足了我們學(xué)習(xí)該系統(tǒng)的強(qiáng)烈愿望。GPL充分體現(xiàn)了Stallman的思想:只要用戶所做的修改是同等自由的,用戶可以自由地使用、拷貝、查詢、重用、修改甚至發(fā)布這個(gè)軟件。通過(guò)這種方式,GPL保證了Lin

7、ux(以及同一許可證下的大量其他軟件)不僅現(xiàn)在自由可用,而且皮后經(jīng)過(guò)任何修改這后都仍然可以自由使用。 Unix是由ATT貝爾實(shí)驗(yàn)室的Ken Thompson和Dennis Ritchie于1969年在一臺(tái)已經(jīng)廢棄了的PDP-7上開發(fā)的;最初它是一個(gè)用匯編語(yǔ)言寫成的單用戶操作系統(tǒng)。后來(lái),他們又在PDP-11上用C語(yǔ)言重新編寫(發(fā)明C語(yǔ)言的部分目的就在于此),把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

8、版本的Unix。與此同時(shí),其它獨(dú)立開發(fā)的Unix版本也開始萌生。Unix不斷發(fā)展了,各種版本被應(yīng)用到不同的計(jì)算機(jī)使用。而Linux最初是專門為基于Intel的個(gè)人計(jì)算機(jī)設(shè)計(jì)的。(1)Linux的昨天 1991年,一名叫Linus 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)行g(shù)cc、bash和很少的一些應(yīng)用程序。后來(lái),他又開始了在因特網(wǎng)上尋求廣泛的幫助。19

9、94年,Linux已經(jīng)升級(jí)到1.0版本。它的源代碼量也呈指數(shù)形式增長(zhǎng),實(shí)現(xiàn)了基本的TCP/IP功能,此時(shí)Linux已經(jīng)擁有大約10萬(wàn)的用戶。(2) Linux的今天 作為一各服務(wù)器級(jí)的操作系統(tǒng),Linux已經(jīng)成熟了。現(xiàn)在的Linux內(nèi)核由150多行代碼組成,能作為Web服務(wù)器平臺(tái),也為越來(lái)越多的商業(yè)用戶提供文件和打印服務(wù)。它既被當(dāng)作郵件服務(wù)器的一種候選平臺(tái),也被當(dāng)作一種強(qiáng)壯而安全的防火墻。 Linux的企業(yè)級(jí)特性,比如支持多處理器、支持大型文件系統(tǒng)、日志文件系統(tǒng)以及密集型計(jì)算和高可用性集群技術(shù),也逐步成熟。 桌面上的Linux也在繼續(xù)完善。KDE桌面提供的圖形用戶界面在易用性和可配置方面都能和

10、微軟的Windows相媲美。(3) Linux的明天 Linux最強(qiáng)大的生命力在于其公開的開發(fā)過(guò)程。每個(gè)人都有可以自由獲取內(nèi)核源程序,每個(gè)人都有要不得以運(yùn)載源程序加以修改,而后他人也可以自由獲取你修改后的源程序。Linux這種獨(dú)特的自由流暢的開發(fā)模型已被命名為bazaar(集市模型)。Bazaar開發(fā)模型通過(guò)重視實(shí)驗(yàn),征集并充分利用早期的反饋,對(duì)巨大數(shù)量的腦力資源進(jìn)行平衡配置,可以開發(fā)出更優(yōu)秀的軟件。本聯(lián)盟就是想通過(guò)bazaar開發(fā)模型,在網(wǎng)上召集一些Linux的愛(ài)好者,開發(fā)出更優(yōu)秀的操作系統(tǒng)或軟件。 二、實(shí)驗(yàn)?zāi)康?.1掌握ARM Linux交叉編譯平臺(tái)的搭建2.2掌握Makefile文件的編

11、寫2.3掌握編譯工具arm-linux-gcc2.4熟悉程序下載過(guò)程三、實(shí)驗(yàn)步驟3.1交叉編譯平臺(tái)的安裝(1) 考慮到現(xiàn)今Linux平臺(tái)發(fā)展,交叉編譯平臺(tái)編統(tǒng)一為arm-linux-gcc-4.4.3(2) 在windows系統(tǒng)下,建立一個(gè)共享目錄,如:e:/linux_file(3) 將光盤目錄linux中的arm-linux-gcc-4.4.3.tar.gz 復(fù)制到e:/linux_file(4) 注意在進(jìn)行虛擬機(jī)設(shè)置時(shí)使共享目錄的有效,并添加共享目錄e:/linux_file(5) 進(jìn)入linux操作系統(tǒng),root目錄下建立一個(gè)Armcode的子目錄,將共享目錄下的文件arm-linux

12、-gcc-4.4.3.tar.gz復(fù)制到該目錄(6) 然后進(jìn)入到該目錄,執(zhí)行解壓命令:#cd /root/Armcode; #tar xvzf arm-linux-gcc-4.4.3.tgz C /; 注意:C 后面有個(gè)空格,并且C 是大寫的,它是英文單詞“Change”的第一個(gè)字母,在此是改變目錄的意思。(7) 執(zhí)行該命令,將把a(bǔ)rm-linux-gcc 安裝到/opt/FriendlyARM/toolschain /4.4.3/bin 目錄。(8) 把編譯器路徑加入系統(tǒng)環(huán)境變量,運(yùn)行命令:#gedit /root/.bashrc編輯/root/.bashrc 文件,在最后一行添加:expo

13、rt PATH=$PATH: /opt/FriendlyARM/toolschain/4.4.3/bin(9) 重新登錄系統(tǒng)(不必重啟機(jī)器,開始->logout 即可),使以上設(shè)置生效,在命令行輸入:arm-linux-gcc v,會(huì)出現(xiàn)如下信息,這說(shuō)明交叉編譯環(huán)境已經(jīng)成功安裝。四、設(shè)計(jì)原理4.1設(shè)計(jì)原理流程網(wǎng)絡(luò)編程,一定離不開套接口;那什么是套接口呢?在Linux下,所有的I/O操作都是通過(guò)讀寫文件描述符而產(chǎn)生的,文件描述符是一個(gè)和打開的文件相關(guān)聯(lián)的整數(shù),這個(gè)文件并不只包括真正存儲(chǔ)在磁盤上的文件,還包括一個(gè)網(wǎng)絡(luò)連接、一個(gè)命名管道、一個(gè)終端等,而套接口就是系統(tǒng)進(jìn)程和文件描述符通信的一種方

14、法。服務(wù)器端:(1)創(chuàng)建一個(gè)socket,用函數(shù)socket();(2)綁定IP地址、端口等信息島socket上,用函數(shù)bind();(3)設(shè)置應(yīng)許的最大連接數(shù),用函數(shù)listen();(4)接收客戶端上來(lái)的鏈接,用函數(shù)accept();(5)接收數(shù)據(jù),用recv();(6)關(guān)閉網(wǎng)絡(luò)鏈接。客戶端:(1)創(chuàng)建一個(gè)socket,用函數(shù)socket();(2)設(shè)置要連接的對(duì)方的IP地址和端口等屬性;(3)連接服務(wù)器,用函數(shù)connect();(4)發(fā)送數(shù)據(jù),用函數(shù)send();(5)關(guān)閉網(wǎng)絡(luò)連接。4.2程序流程分析(1)創(chuàng)建Socket不管是客戶端還是服務(wù)器端,都需要先創(chuàng)建一個(gè)socket。調(diào)用方式

15、為:int socket(int domain,int type,int protocol)功能:創(chuàng)建一個(gè)新的套接字。參數(shù):domain: 指明所使用的協(xié)議族 type: 指明套接字的類型 protocol: 通常賦值“0”返回值:成功時(shí),返回一個(gè)整形socket描述符;失敗時(shí),返回-1。設(shè)計(jì)過(guò)程具體調(diào)用為:sock_fd = socket(AF_INET,SOCK_STREAM,0);(2)服務(wù)器端使用的函數(shù)1)int bind(int sockfd, struct sockaddr *my_addr, int addrlen)sockfd:是由socket調(diào)用返回的文件描述符。Addrle

16、n:是sockaddr結(jié)構(gòu)的長(zhǎng)度。my_addr:是一個(gè)指向sockaddr的指針。由于我們主要使用Internet 所以sin_family 一般為AF_INET,sin_addr設(shè)置為INADDR_ANY表示可以和任何的主機(jī)通信,sin_port是要監(jiān)聽(tīng)的端口號(hào),sin_zero8是用來(lái)填充的。bind 將本地的端口同socket 返回的文件描述符捆綁在一起,成功是返回0。2)int listen(int sockfd,int backlog)sockfd:是bind后的文件描述符。backlog:設(shè)置請(qǐng)求排隊(duì)的最大長(zhǎng)度,當(dāng)有多個(gè)客戶端程序和服務(wù)端相連時(shí),使用這個(gè)表示可以介紹的排隊(duì)長(zhǎng)度。l

17、isten函數(shù)將bind的文件描述符變?yōu)楸O(jiān)聽(tīng)套接字,返回的情況和bind一樣。3)int accept(int sockfd, struct sockaddr *addr,int *addrlen)sockfd:是listen后的文件描述符。addr,addrlen:是用來(lái)給客戶端的程序填寫的,服務(wù)器端只要傳遞指針就可以了。bind、listen和accept是服務(wù)器端用的函數(shù),accept調(diào)用時(shí)服務(wù)器端的程序會(huì)一直阻塞到有一個(gè)客戶程序發(fā)出了連接。accept成功時(shí)返回最后的服務(wù)器端的文件描述符,這個(gè)時(shí)候服務(wù)器端可以向該描述符寫信息了,失敗時(shí)返回-1。4)int connect(int soc

18、kfd, struct sockaddr * serv_addr,int addrlen)sockfd:socket返回的文件描述符。serv_addr:儲(chǔ)存了服務(wù)器端的連接信息,in_add是服務(wù)端的地址。addrlen:serv_addr的長(zhǎng)度。connect函數(shù)是客戶端用來(lái)同服務(wù)端連接的,成功時(shí)返回0,sockfd是同服務(wù)端通訊的文件描述符,失敗時(shí)返回-1。(3)客戶端使用的函數(shù)1)connect( SOCKET s, const struct sockaddr FAR* name, int namelen);s:標(biāo)識(shí)一個(gè)未連接套接口的描述字。name:欲進(jìn)行連接的端口名。namelen

19、:名字長(zhǎng)度。若無(wú)錯(cuò)誤發(fā)生,則connect()返回非0。否則的話,返回SOCKET_ERROR錯(cuò)誤,應(yīng)用程序可通過(guò)WSAGetLastError()獲取相應(yīng)錯(cuò)誤代碼。對(duì)阻塞套接口而言,若返回值為SOCKET_ERROR則應(yīng)用程序調(diào)用WSAGetLsatError()。如果它指出錯(cuò)誤代碼為WSAEWOULDBLOCK,則您的應(yīng)用程序可以:a用select(),通過(guò)檢查套接口是否可寫,來(lái)確定連接請(qǐng)求是否完成。b如果您的應(yīng)用程序使用基于消息的WSAAsynSelect()來(lái)表示對(duì)連接事件的興趣,則當(dāng)連接操作完成后,您會(huì)收到一個(gè)FD_CONNECT消息。2)send( SOCKET s, const

20、char FAR* buf, int len, int flags);s:一個(gè)用于標(biāo)識(shí)已連接套接口的描述字。buf:包含待發(fā)送數(shù)據(jù)的緩沖區(qū)。len:緩沖區(qū)中數(shù)據(jù)的長(zhǎng)度。flags:調(diào)用執(zhí)行方式。五、網(wǎng)絡(luò)套接字(socket)的概念 5.1 Socket 介紹 上世紀(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è)通信端口, 可以通過(guò)這個(gè)端口與任

21、何一個(gè)具有Socket 接口的計(jì)算機(jī)通信。應(yīng)用程序在網(wǎng)絡(luò)上傳輸,接收的信息都通過(guò)這個(gè)Socket 接口來(lái)實(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)鍵因素。5.2 Socket 原理簡(jiǎn)介當(dāng)用電話與他人通信時(shí), 必須拿起話筒, 撥叫對(duì)方的電話號(hào)碼, 然后等待對(duì)方的應(yīng)答; 當(dāng)雙方

22、進(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)碼。通過(guò)在程序中指定遠(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)

23、用程序通過(guò)編程接口來(lái)訪問(wèn)TCP /IP。套接字( Socket) 是介于網(wǎng)絡(luò)應(yīng)用層和傳輸層之間的編程接口, 套接字接口提供了訪問(wèn)下層通信協(xié)議的大量系統(tǒng)調(diào)用和相應(yīng)的數(shù)據(jù)結(jié)構(gòu)。在Linux 中, 套接字接口是應(yīng)用程序訪問(wèn)下層的網(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ò)模型中的地位如圖4所示。 圖4 socket在TCP/IP網(wǎng)絡(luò)模型中的示意圖Socket 分為以下三種類型: 流式套接字( Stream Socket) : 是最常用的套接字類型, 文件傳送協(xié)議( FTP) 即使用流

24、式套接字。提供一個(gè)面向連接、可靠的數(shù)據(jù)傳輸服務(wù), 數(shù)據(jù)無(wú)差錯(cuò)、無(wú)重復(fù)地發(fā)送, 且按發(fā)送順序接收。內(nèi)設(shè)流量控制, 避免數(shù)據(jù)流超限; 數(shù)據(jù)被看作是字節(jié)流, 無(wú)長(zhǎng)度限制。數(shù)據(jù)報(bào)套接字(Datagram Socket) : TCP /IP 協(xié)議族中的UDP 協(xié)議使用此類接口, 它是無(wú)連接的服務(wù),數(shù)據(jù)通過(guò)相互獨(dú)立的報(bào)文進(jìn)行傳輸, 提供了一個(gè)無(wú)連接服務(wù)。數(shù)據(jù)包以獨(dú)立包形式被發(fā)送, 不提供無(wú)錯(cuò)保證, 數(shù)據(jù)可能丟失或重復(fù), 并且接收順序混亂。原始數(shù)據(jù)報(bào)套接字(Raw Socket) : 該接口允許對(duì)較低層協(xié)議, 如IP、ICMP 直接訪問(wèn)。常用于檢驗(yàn)新的協(xié)議實(shí)現(xiàn)或訪問(wèn)。5.3 Socket 通信過(guò)程與程序開發(fā)

25、 (1) Socket 通信過(guò)程 基于TCP 可靠連接的客戶與服務(wù)器連接進(jìn)程流程圖如圖 客戶與服務(wù)器的socket連接步驟流程 Socket 工作過(guò)程如下: 服務(wù)器首先啟動(dòng), 通過(guò)調(diào)用Socket (), 建立一個(gè)Socket, 然后調(diào)用bind()將該Socket 和本地網(wǎng)絡(luò)地址綁系在一起, 再調(diào)用listen()使Socket 做好偵聽(tīng)的準(zhǔn)備, 并規(guī)定它的請(qǐng)求隊(duì)列的長(zhǎng)度,之后就調(diào)用accept()來(lái)接收連接。客戶在建立Socket 后就可調(diào)用connect()和服務(wù)器建立連接。連接一旦建立,客戶機(jī)和服務(wù)器之間就可以通過(guò)調(diào)用send()和recv()來(lái)發(fā)送和接收數(shù)據(jù)。最后, 待數(shù)據(jù)傳送結(jié)束后

26、, 雙方調(diào)用close()關(guān)閉Socket。 (2)Socket 通信程序開發(fā)下面詳細(xì)說(shuō)明Socket 通信程序的開發(fā)過(guò)程:1) 步驟1: 建立套接口socket() int sockfd = socket ( int domain, int type, intprotocol) , 其中domain 參數(shù)指定socket 協(xié)議族, 包括PF_LOACL 和PF_INET, PF_LOACL 表示使用本地套接口, PF_INET 表示使用Internet 套接口。Type 參數(shù)定義了套接口的類型, 包括SOCK_STREAM 和SOCK_DGRAM, SOCK_STREAM 指定為流套接口,S

27、OCK_DGRAM指定為數(shù)據(jù)報(bào)套接口。protocol 通常賦值“0”, 意味套接口使用TCP /IP 協(xié)議。socket()調(diào)用返回一個(gè)整型socket 描述符, 可以在后面的調(diào)用使用它, 當(dāng)其值為- 1 時(shí), 說(shuō)明有錯(cuò)誤發(fā)生。2) 步驟2: 綁定套接口bind() 當(dāng)用socket()建立套接口后, 該套接口還是處于無(wú)名狀態(tài)的, 無(wú)名套接口就象沒(méi)有號(hào)碼的電話一樣,別人無(wú)法向發(fā)送信息( 在同一linux 內(nèi)核下可實(shí)現(xiàn)無(wú)名狀態(tài)下通信) 。為了像電話分配電話號(hào)碼一樣, 可以通過(guò)bind()為建立的套接口綁定一個(gè)名字分配地址。這一步對(duì)客戶端不是必需的。int bind ( int sockfd,

28、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, 我們可以通過(guò)查看errno 的值來(lái)了解錯(cuò)誤的原因。需要指出的是, 可以用下面的賦值實(shí)現(xiàn)自動(dòng)獲得本機(jī)IP 地址和隨機(jī)獲取一個(gè)沒(méi)有被占用的端口號(hào):my_addr.sin_port=0; /< 系統(tǒng)隨機(jī)選擇一個(gè)未被使用的端口號(hào)< /m

29、y_addr.sin_addr.s_addr=INADDR_ANY; /< 填入本機(jī)IP 地址< /通過(guò)將my_addr.sin_port 置為0, 函數(shù)會(huì)自動(dòng)為選擇一個(gè)未占用的端口來(lái)使用。同樣, 通過(guò)將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è)沒(méi)有被占用的端口號(hào)。( 3) 步驟3:

30、請(qǐng)求連接connect()當(dāng)客戶端綁定地址后, 發(fā)送請(qǐng)求連接信號(hào)connect()來(lái)與遠(yuǎn)端服務(wù)器建立一個(gè)TCP 連接。connect()函數(shù)原型為:int connect ( int sockfd, struct sockaddr<serv_addr, int addrlen) ;sockfd 是目的服務(wù)器的socket 描述符; serv_addr是包含目的機(jī)IP 地址和端口號(hào)的指針, addrlen 為結(jié)構(gòu)的大小。遇到錯(cuò)誤時(shí)返回- 1, 并且errno 中包含相應(yīng)的錯(cuò)誤碼。進(jìn)行客戶端程序設(shè)計(jì)無(wú)須調(diào)用bind(), 因?yàn)檫@種情況下只需知道目的機(jī)器的IP 地址, 而客戶通過(guò)哪個(gè)端口與服務(wù)

31、器建立連接并不需要關(guān)心, 內(nèi)核會(huì)自動(dòng)選擇一個(gè)未被占用的端口供客戶端來(lái)使用。( 4) 步驟4: 監(jiān)聽(tīng)連接listen()在服務(wù)器端程序中, 當(dāng)socket 與某一端口捆綁以后, 就需要監(jiān)聽(tīng)該端口, 以便對(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ì)列中等待accept()它們。backlog 對(duì)隊(duì)列中等待服務(wù)的請(qǐng)求的數(shù)目進(jìn)行了限制, 對(duì)于小型服務(wù)器, 隊(duì)列長(zhǎng)度應(yīng)該為5 或是稍大一些的值, 而對(duì)于網(wǎng)站服務(wù)

32、器, 我們就需要更大的值, 比如說(shuō)16 或是更大。當(dāng)listen 遇到錯(cuò)誤時(shí)返回- 1, errno 被置為相應(yīng)的錯(cuò)誤碼。步驟5: 連接端口的服務(wù)請(qǐng)求 當(dāng)某個(gè)客戶端試圖與服務(wù)器監(jiān)聽(tīng)的端口連接時(shí),該連接請(qǐng)求將排隊(duì)等待服務(wù)器accept()它。通過(guò)調(diào)用accept()函數(shù)為其建立一個(gè)連接, accept()函數(shù)將返回一個(gè)新的socket 描述符, 來(lái)供這個(gè)新連接來(lái)使用。而服務(wù)器可以繼續(xù)在以前的那個(gè)socket 上監(jiān)聽(tīng), 同時(shí)可以在新的socket 描述符上進(jìn)行數(shù)據(jù)send ()( 發(fā)送) 和recv()( 接收) 操作。int accept( int sockfd, void <addr,

33、int <addrlen) ;sockfd 是被監(jiān)聽(tīng)的socket 描述符, addr 通常是一個(gè)指向sockaddr_in 變量的指針, 該變量用來(lái)存放提出連接請(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 值。accept()之前, 通常將addrlen 初始化為0。步驟6: 數(shù)據(jù)傳輸send()和recv()send()和recv()這兩個(gè)函數(shù)是用于面向連接的socket 上進(jìn)行數(shù)據(jù)傳輸。send()函數(shù)原型為:i

34、nt send ( int sockfd, const void <msg, int len, intflags) ;sockfd 是想用來(lái)傳輸數(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ì)少于希望發(fā)送的數(shù)據(jù)。所以需要對(duì)send()的返回值進(jìn)行測(cè)量。當(dāng)send()返回值與len 不匹配時(shí), 應(yīng)該對(duì)這種情況進(jìn)行處理。recv()函數(shù)原型為:int recv ( int sockfd, void <buf, int l

35、en, 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: 關(guān)閉連接close() 當(dāng)所有的數(shù)據(jù)操作結(jié)束以后, 可以調(diào)用close()函數(shù)來(lái)釋放該socket, 從而停止在該socket 上的任何數(shù)據(jù)操作。5.4Socket簡(jiǎn)要步驟如下:(1)建立一個(gè)Socket。(2)按要求配置socket,將socket連接到遠(yuǎn)程主機(jī)或給socket指定以各本地協(xié)議端口。(3)按要求通過(guò)

36、socket發(fā)送和接受數(shù)據(jù)。(4)關(guān)閉此socket。這是通過(guò)Socket實(shí)現(xiàn)點(diǎn)對(duì)點(diǎn)需要掌握的4個(gè)編程要點(diǎn)。5.5多線程的概念 上述點(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ù)通過(guò)一個(gè)端口地址發(fā)送和接收。 對(duì)于多個(gè)并發(fā)的任務(wù)需要?jiǎng)?chuàng)建多個(gè)線程或線程去實(shí)現(xiàn)。使用一個(gè)進(jìn)程去完成發(fā)送信息是沒(méi)有問(wèn)題的,因?yàn)榘l(fā)送總是主動(dòng)的;而使用同一個(gè)進(jìn)程再去完成接受信息去不一定會(huì)成功,因?yàn)榻邮苄畔⑹潜粍?dòng)的,所以當(dāng)沒(méi)有信息可以接收時(shí),該進(jìn)程就會(huì)被阻塞,從而

37、導(dǎo)致發(fā)送任務(wù)也一起被阻塞。同一個(gè)端口的發(fā)送和接收是兩個(gè)并發(fā)任務(wù),應(yīng)該由兩個(gè)不同的任務(wù)去分別完成信息的發(fā)送和接收。這樣,當(dāng)接收信息任務(wù)因沒(méi)有信息而被阻塞時(shí),不至于影響發(fā)送任務(wù)的執(zhí)行。那么,發(fā)送和接收兩個(gè)任務(wù)是使用兩個(gè)進(jìn)程還是兩個(gè)進(jìn)程去完成呢?在網(wǎng)絡(luò)通信中,端口地址是以進(jìn)程為單位進(jìn)程分配的,而一個(gè)進(jìn)程與外界的消息發(fā)送與接收必須通過(guò)分配給它的同一個(gè)端口進(jìn)行。因此,不能通過(guò)創(chuàng)建進(jìn)程方式來(lái)解決上訴問(wèn)題,因?yàn)閮蓚€(gè)進(jìn)程會(huì)分別對(duì)應(yīng)兩個(gè)不同的端口,而發(fā)送和接收必須使用同一端口。線程不是資源分配的單位,所以如果使用兩個(gè)線程不會(huì)對(duì)線程分配新的端口。因此,本實(shí)驗(yàn)需要使用兩個(gè)線程去分別完成發(fā)送和接收信息的任務(wù),這兩個(gè)線

38、程共享其進(jìn)程擁有的統(tǒng)一個(gè)端口地址。由于創(chuàng)建進(jìn)程的進(jìn)程本身會(huì)作為一個(gè)線程來(lái)調(diào)度,所以只需要再創(chuàng)建一個(gè)線程專門負(fù)責(zé)接收信息就可以了。因此,對(duì)于從每個(gè)客戶端發(fā)來(lái)的請(qǐng)求,服務(wù)器端都要?jiǎng)?chuàng)建相應(yīng)的線程去接收并處理;同理,對(duì)于客戶端而言,也要?jiǎng)?chuàng)建一個(gè)線程去讀取服務(wù)器端發(fā)來(lái)的信息。六、系統(tǒng)實(shí)現(xiàn)6.1 Linux提供的有關(guān)Socket的系統(tǒng)調(diào)用(1)Socket() 作用:socket函數(shù)為客戶機(jī)或服務(wù)器創(chuàng)建一個(gè)sokcet 格式: int socket(int family,int type,int protocol); 參數(shù)說(shuō)明: Family:表示地址族,可以去AF_UNLX和AF_INT。 其中,AF_

39、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é)議,這樣提供按順序的、可靠的、雙向、面向連接的比特流;SOCKE_DGRAM表明使用的是UDP協(xié)議,這樣只會(huì)提供定長(zhǎng)、不可靠、無(wú)連接的通信。(2)bind( ) 格式: int bind(int sockfd,struct sockaddr *addr,int addrlen); 參數(shù)說(shuō)明: Sockfd:socket

40、的文件描述符號(hào)。 Sockaddr:表示名字所用的一個(gè)數(shù)據(jù)結(jié)構(gòu),用來(lái)保存地址(包括IP地址和端口) Addrlen:設(shè)置結(jié)構(gòu)大小長(zhǎng)度。(3)listen() 格式: int listen(int sockfd, int backlog); 作用:監(jiān)聽(tīng)連接信號(hào),和accepted函數(shù)合同。 參數(shù)說(shuō)明: 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函

41、數(shù)合用,監(jiān)聽(tīng)信息、接收客戶端請(qǐng)求。 參數(shù)說(shuō)明: Sockfd:表示socket的文件描述符。 Addr:表示指向局部的數(shù)據(jù)結(jié)構(gòu)struct sockaddr-in的指針。 Addrlen:表示地址的長(zhǎng)度。(5)connect() 格式: int connect( int sockfd , struct sockaddr *serv_addr , int addrlen); 作用:在面向連接的系統(tǒng)中客戶及連接服務(wù)器時(shí)使用,connect必須在bind后使用。 參數(shù)作用: Sockfd:表示socket的文件描述符。 Serv-addr:表示村訪目的端口和ip地址(套接字)的數(shù)據(jù)結(jié)構(gòu)。(6)sen

42、d() 和 recv() 格式1: Int send (int sockfd, const vod *msg,int len, int flags); 功能:發(fā)送信息。 格式2: Int recv (int sockfd , void *buf,int len, usigned int flags); 作用:用于流式socket、數(shù)據(jù)報(bào)socket內(nèi)部之間的通信。(7)close( ) 和 shutdown ( ) 格式: Close( int sockfd)或 Int shutdown(int sockfd , int how); 參數(shù)說(shuō)明: How的值為下面一種: 0-不允許繼續(xù)接收; 1

43、-不允許繼續(xù)發(fā)送; 2-不允許繼續(xù)發(fā)送和接收。(8)有關(guān)線程的系統(tǒng)調(diào)用函數(shù)pthread_create()、pthread_join()。6.2 監(jiān)聽(tīng)連接 利用socket、bind、listen建立連接,步驟是:1、先用socket函數(shù)初始化socket,創(chuàng)建新的sockfd。 Sockfd = socket(AF_INT,SOCK_STREAM,0)2、此步驟涉及到IP地址及其處理過(guò)程。參數(shù)說(shuō)明: inet_addr 函數(shù) INADDR_ANY該函數(shù)把由小數(shù)點(diǎn)分開的十進(jìn)制IP地址轉(zhuǎn)為unsinged long 類型,而在實(shí)驗(yàn)中所使用的為INADDR_ANY,使用利用自已的IP地址自動(dòng)填充。

44、 (1)利用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,(stuct sockaddr*)&my_addr,sizeof(stuct sockaddr);/*sockfd 是分配的socket名字,my-addr則便是分配好的端口與IP,用bind綁定*/(2)利用listen監(jiān)聽(tīng)請(qǐng)求6.3發(fā)送請(qǐng)求(1)利

45、用gethostbyname獲取主機(jī)信息。(2)初始化socket端口。(3)利用connect函數(shù)將自己的IP地址等信息發(fā)送到主機(jī),等待主機(jī)調(diào)用accept函數(shù)來(lái)接受請(qǐng)求。6.4主機(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é)束子線程。七、 運(yùn)行效果程序測(cè)試環(huán)境:linux、unix、debian等操作系統(tǒng)。測(cè)試軟件:putty、vmware虛擬機(jī)(1) 在編寫完TCP服務(wù)端程序server.c后,用 gcc lpthread o ser

46、ver.c server 生成程序server。(2) 在編寫完TCP客戶端程序client.c后,用gcc lpthread 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ā)送信息

47、的方式相互發(fā)送和接收信息。1) 客戶端、服務(wù)器端窗皆通過(guò)鍵盤輸入消息內(nèi)容平回車,以發(fā)送消息給對(duì)方;2) 消息中若使用空格,則作為本條消息結(jié)束及下一條消息的開始;3) 輸入exit則推出運(yùn)行。開始運(yùn)行后,服務(wù)器端窗口的執(zhí)行順序?yàn)椋?) 鍵入“Hello,world!”發(fā)送給客戶端2) 接收客戶端發(fā)來(lái)的兩個(gè)消息;3) 鍵入“OK!”發(fā)送個(gè)客戶端;4) 輸入exit結(jié)束。服務(wù)器端運(yùn)行結(jié)果如實(shí)驗(yàn)圖所示。服務(wù)器端窗口開始運(yùn)行后,客戶端窗口的執(zhí)行順序?yàn)椋?) 接收服務(wù)器端發(fā)來(lái)的消息“Hello,world!”;2) 發(fā)送消息“hello!“和”Good!”給服務(wù)器端;3) 接收服務(wù)器發(fā)來(lái)的消息“OK!”;

48、4) 鍵入exit結(jié)束。客戶端運(yùn)行結(jié)果如實(shí)驗(yàn)圖4-2所示。客戶端窗口上述運(yùn)行結(jié)果表明,客戶端與服務(wù)器端之間傳遞的消息已被對(duì)方成功接收。 附錄:(1)編寫服務(wù)器端程序 tcp_server.c #include "common.h"void sig(int signum)psignal(signum,"Catch signal:");signal(signum,sig);int main (int argc, char *argv)int sock_fd,conn_fd;struct sockaddr_in server_addr,client_addr;

49、socklen_t addrlen = ADDR_SIZE;int wc = -1,rc = -1;char buffer_rBUFFER_SIZE,buffer_wBUFFER_SIZE;int i = 1;pid_t pt;int val;fd_set readfds;struct timespec t_val;int max_fd;int ret;sigset_t sigset,newset;sigemptyset(&sigset);sigemptyset(&newset);sigaddset(&sigset,SIGINT);sigaddset(&sigs

50、et,SIGALRM);sock_fd = socket(AF_INET,SOCK_STREAM,0);if(sock_fd = -1)Err_sys("Server socket:")bzero(&server_addr,ADDR_SIZE);server_addr.sin_family = AF_INET;server_addr.sin_port = htons(Server_port);server_addr.sin_addr.s_addr = htonl(INADDR_ANY);setsockopt(sock_fd,SOL_SOCKET,SO_REUSEAD

51、DR,(void *)&i,sizeof(i);if(bind(sock_fd,(struct sockaddr *)&server_addr,addrlen) = -1)Err_sys("Server bind:")if(listen(sock_fd,2) = -1)Err_sys("Server listen:")while(RUNNING)conn_fd = accept(sock_fd,(struct sockaddr *)&client_addr,&addrlen);sleep(3);printf("a

52、ccept success!n");if(conn_fd = -1)fprintf(stderr,"Server accept:%s",strerror(errno);printf("Connect client ip:%s port:%dn",inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port);if(pt = fork() = -1)Err_sys("Server fork:")else if(pt > 0)close(conn_fd);elsec

53、lose(sock_fd);signal(SIGALRM,sig);printf("signal successn");sigprocmask(SIG_BLOCK,&sigset,NULL);raise(SIGALRM);sleep(10);while(RUNNING)FD_ZERO(&readfds);FD_SET(0,&readfds);FD_SET(conn_fd,&readfds); t_val.tv_sec = 7;t_val.tv_nsec = 0; max_fd = conn_fd;if(ret = pselect(max_fd

54、 + 1,&readfds,NULL,NULL,&t_val,&sigset) = -1)Err_sys("Server select:")else if(ret = 0)Err_sys ("Select timeoutn");continue;elseif(FD_ISSET(conn_fd,&readfds)memset(buffer_r,0,BUFFER_SIZE);rc = recv(conn_fd,buffer_r,BUFFER_SIZE,0);if(rc <= 0)fprintf(stderr,"Server recv:%sn",strerror(errno);FD_CLR(conn_fd,&readfds);close(conn_fd);printf("Server recv:%

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝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ù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 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)論