2023年全國(guó)碩士研究生考試考研英語(yǔ)一試題真題(含答案詳解+作文范文)_第1頁(yè)
已閱讀1頁(yè),還剩39頁(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、<p>  linux TCP服務(wù)器/客戶端通信程序</p><p>  摘要:隨著計(jì)算機(jī)網(wǎng)絡(luò)的不斷發(fā)展,網(wǎng)絡(luò)編程變得越來(lái)越重要,除了簡(jiǎn)單的WEB編程外,還包括利用套接字(Socket)進(jìn)行客戶/服務(wù)器應(yīng)用程序的設(shè)計(jì)。本文先對(duì)與套接字相關(guān)的概念和函數(shù)作了一般性介紹,并提出多線程的編程方法和設(shè)計(jì)流程,也就具體的工程實(shí)例進(jìn)行了流程分析。本文中,對(duì)計(jì)算機(jī)的網(wǎng)絡(luò)模型進(jìn)行了簡(jiǎn)要的分析,并對(duì)TCP的握手模型進(jìn)行了概

2、述;在多線程編程中,本文詳細(xì)分析了多線程的互斥模型,講解了多種線程之間的同步方法,并在程序設(shè)計(jì)中得到體現(xiàn),詳細(xì)講述了Linux中的TCP服務(wù)器/客戶端通信程序,并對(duì)結(jié)果進(jìn)行了驗(yàn)證。</p><p>  關(guān)鍵字:網(wǎng)絡(luò)編程 ;多線程;套接字</p><p><b>  目 錄</b></p><p><b>  緒論1</b>

3、;</p><p><b>  1. 課程背景1</b></p><p>  2. 選題的目的和意義1</p><p>  3. 國(guó)內(nèi)外研究現(xiàn)狀1</p><p>  4. 主要研究?jī)?nèi)容1</p><p>  第1章 需求分析3</p><p>  1.1 設(shè)計(jì)目

4、的3</p><p>  1.2 課題要求3</p><p>  1.3 任務(wù)分析3</p><p>  第2章 環(huán)境搭建4</p><p>  2.1 Ubuntu系統(tǒng)安裝4</p><p>  2.2 開(kāi)發(fā)環(huán)境搭建7</p><p>  2.2.1 NFS環(huán)境介紹7</p

5、><p>  2.2.2 NFS安裝7</p><p>  2.2.3 掛載NFS文件系統(tǒng)7</p><p>  2.2.4 交叉工具安裝8</p><p>  第3章 軟件設(shè)計(jì)9</p><p>  3.1 TCP/IP協(xié)議9</p><p>  3.1.1 網(wǎng)絡(luò)模型9</p&g

6、t;<p>  3.1.2 TCP連接9</p><p>  3.2 多線程編程10</p><p>  3.3 Socket網(wǎng)絡(luò)編程模型12</p><p>  3.3.1 TCP Server編程模型12</p><p>  3.3.2 TCP Client編程模型13</p><p>  

7、3.4 程序設(shè)計(jì)13</p><p>  3.4.1 主要內(nèi)容13</p><p>  3.4.2 服務(wù)器端程序設(shè)計(jì)14</p><p>  3.4.3 客戶端程序設(shè)計(jì)16</p><p>  第4章 綜合測(cè)試18</p><p>  4.1 功能測(cè)試18</p><p><b

8、>  第5章 結(jié)論20</b></p><p><b>  參考文獻(xiàn)21</b></p><p>  附錄一 服務(wù)器端程序22</p><p>  附錄二 客戶端程序32</p><p><b>  緒論</b></p><p>  Linux經(jīng)歷了

9、20多年的發(fā)展,已經(jīng)成為了一個(gè)功能強(qiáng)大而穩(wěn)定的操作系統(tǒng),在嵌入式系統(tǒng)中也得到廣泛的運(yùn)用,伴隨著物聯(lián)網(wǎng)技術(shù)的普及,網(wǎng)絡(luò)通信在嵌入式系統(tǒng)中扮演著舉足輕重的作用。</p><p><b>  課程背景</b></p><p>  隨著時(shí)代的發(fā)展,網(wǎng)絡(luò)通信在我們的生活中愈來(lái)愈重要,在互聯(lián)網(wǎng)技術(shù)基礎(chǔ)上延伸和擴(kuò)展來(lái)的物聯(lián)網(wǎng)技術(shù),正逐漸改變著我們的世界?;ヂ?lián)網(wǎng)在現(xiàn)實(shí)生活中的應(yīng)用很廣

10、泛,互聯(lián)網(wǎng)給我們的現(xiàn)實(shí)生活帶來(lái)了很大的方便;互聯(lián)網(wǎng)是全球性的,這也就意味著我們能夠打破時(shí)空的界限,通過(guò)互聯(lián)網(wǎng)接觸到世界的每一個(gè)角落;因?yàn)榛ヂ?lián)網(wǎng)的強(qiáng)大力量,這個(gè)時(shí)代的文明發(fā)展得到極大地提高。</p><p><b>  選題的目的和意義</b></p><p>  由于互聯(lián)網(wǎng)超乎尋常的強(qiáng)大力量,改變了這個(gè)時(shí)代的交流方式,改變著人們的生活,未來(lái),我們還將在互聯(lián)網(wǎng)領(lǐng)域得到更

11、多的進(jìn)步,會(huì)影響生活中的方方面面。</p><p><b>  國(guó)內(nèi)外研究現(xiàn)狀</b></p><p>  互聯(lián)網(wǎng)從誕生至今,讓人類文明得到巨大的推動(dòng),伴隨著互聯(lián)網(wǎng)的發(fā)展,各種依托互聯(lián)網(wǎng)的技術(shù)得到迅速發(fā)展,Linux操作系統(tǒng)依據(jù)其優(yōu)良的性能和網(wǎng)絡(luò)功能,在各個(gè)領(lǐng)域都得到極大的普及。21世紀(jì),是互聯(lián)網(wǎng)發(fā)展的有一個(gè)階段,我們國(guó)家已經(jīng)將互聯(lián)網(wǎng)的發(fā)展提升到了戰(zhàn)略高度,明確表示要

12、建成互聯(lián)網(wǎng)強(qiáng)國(guó),我國(guó)到目前為止,已經(jīng)誕生了一大批優(yōu)秀的互聯(lián)網(wǎng)企業(yè),全世界都將在互聯(lián)網(wǎng)的推動(dòng)下,進(jìn)入一個(gè)全新的時(shí)代。</p><p><b>  主要研究?jī)?nèi)容</b></p><p>  設(shè)計(jì)TCP服務(wù)器程序,使用多線程實(shí)現(xiàn)”生產(chǎn)者-消費(fèi)者“模型,建立TCP服務(wù)器,響應(yīng)客戶端請(qǐng)求,發(fā)送客戶端指定的請(qǐng)求數(shù)據(jù)。</p><p><b>  

13、主要包括以下內(nèi)容:</b></p><p>  創(chuàng)建線程持續(xù)產(chǎn)生數(shù)據(jù),數(shù)據(jù)包含(學(xué)號(hào),姓名(拼音),年齡,身高,體重,當(dāng)前系統(tǒng)時(shí)間(納秒數(shù))使用gettimeofday(),可使用隊(duì)列/多維數(shù)組存儲(chǔ)數(shù)據(jù);</p><p>  創(chuàng)建TCP服務(wù)器線程,響應(yīng)多個(gè)客戶端的連接,讀取隊(duì)列/數(shù)組,向客戶端發(fā)送指定“學(xué)號(hào)”的數(shù)據(jù)。設(shè)計(jì)TCP服務(wù)器程序;</p><p>

14、;  創(chuàng)建TCP客戶端接收線程,連接服務(wù)器并請(qǐng)求指定“學(xué)號(hào)”的數(shù)據(jù),接收數(shù)據(jù)并存儲(chǔ)在文件中。要求存儲(chǔ)有意義的數(shù)據(jù),由于TCP是基于字節(jié)流的特征,需要做組包處理;</p><p><b>  需求分析</b></p><p><b>  設(shè)計(jì)目的</b></p><p>  通過(guò)對(duì)專業(yè)知識(shí)的熟練運(yùn)用,理解Linux網(wǎng)絡(luò)編程的

15、流程,了解互聯(lián)網(wǎng)的基本架構(gòu),熟悉多線程編程的思想。同時(shí),通過(guò)本課程設(shè)計(jì),可以培養(yǎng)以下能力:</p><p>  獨(dú)立工作能力與創(chuàng)造力;</p><p>  綜合運(yùn)用專業(yè)及基礎(chǔ)知識(shí)的能力;</p><p>  解決實(shí)際工程技術(shù)問(wèn)題的能力;</p><p>  查閱圖書(shū)資料、產(chǎn)品手冊(cè)和各種工具書(shū)的能力;</p><p> 

16、 書(shū)寫(xiě)技術(shù)報(bào)告和編制技術(shù)資料的能力。</p><p><b>  課題要求</b></p><p>  使用多線程實(shí)現(xiàn)”生產(chǎn)者-消費(fèi)者“模型,建立TCP服務(wù)器,響應(yīng)客戶端請(qǐng)求,發(fā)送客戶端指定的請(qǐng)求數(shù)據(jù)。</p><p><b>  任務(wù)分析</b></p><p>  創(chuàng)建線程持續(xù)產(chǎn)生數(shù)據(jù),數(shù)據(jù)包含

17、(學(xué)號(hào),姓名(拼音),年齡,身高,體重,當(dāng)前系統(tǒng)時(shí)間(納秒數(shù))使用gettimeofday),可使用隊(duì)列/多維數(shù)組存儲(chǔ)數(shù)據(jù)。理解常用的數(shù)據(jù)結(jié)構(gòu),熟練掌握C編程語(yǔ)言。</p><p>  創(chuàng)建TCP服務(wù)器線程,響應(yīng)多個(gè)客戶端的連接,讀取隊(duì)列/數(shù)組,向客戶端發(fā)送指定“學(xué)號(hào)”的數(shù)據(jù),設(shè)計(jì)TCP服務(wù)器程序,掌握網(wǎng)絡(luò)編程中服務(wù)器端的編程流程。</p><p>  創(chuàng)建TCP客戶端接收線程,連接服務(wù)器

18、并請(qǐng)求指定“學(xué)號(hào)”的數(shù)據(jù),接收數(shù)據(jù)并存儲(chǔ)在文件中。要求存儲(chǔ)有意義的數(shù)據(jù),由于TCP是基于字節(jié)流的特征,需要做組包處理。掌握網(wǎng)絡(luò)編程中客戶端的編程流程。</p><p>  最終的目的是熟練掌握網(wǎng)絡(luò)編程的編程方法,理解常用的數(shù)據(jù)結(jié)構(gòu)的基本思想,掌握編程語(yǔ)言,理解多線程編程在實(shí)際工程中的應(yīng)用。</p><p><b>  環(huán)境搭建</b></p><p

19、>  Ubuntu系統(tǒng)安裝</p><p>  考慮到Windows系統(tǒng)的普及程度,本課程實(shí)際將利用虛擬機(jī)來(lái)進(jìn)行開(kāi)發(fā),首先我們需要搭建虛擬機(jī)開(kāi)發(fā)環(huán)境。</p><p><b>  創(chuàng)建虛擬機(jī)</b></p><p><b>  圖2.1.1</b></p><p><b>  選擇操

20、作系統(tǒng)</b></p><p><b>  圖2.1.2</b></p><p>  3.配置處理器和內(nèi)存</p><p><b>  圖2.1.3</b></p><p><b>  圖2.1.4</b></p><p><b>

21、  安裝系統(tǒng)</b></p><p><b>  圖2.1.5</b></p><p><b>  安裝成功界面</b></p><p><b>  圖2.1.6</b></p><p><b>  開(kāi)發(fā)環(huán)境搭建</b></p>

22、<p><b>  NFS環(huán)境介紹</b></p><p>  NFS(Network File System)即網(wǎng)絡(luò)文件系統(tǒng),是FreeBSD支持的文件系統(tǒng)中的一種,它允許網(wǎng)絡(luò)中的計(jì)算機(jī)之間通過(guò)TCP/IP網(wǎng)絡(luò)共享資源。在NFS的應(yīng)用中,本地NFS的客戶端應(yīng)用可以透明地讀寫(xiě)位于遠(yuǎn)端NFS服務(wù)器上的文件,就像訪問(wèn)本地文件一樣。</p><p><b&g

23、t;  NFS安裝</b></p><p>  1.NFS是網(wǎng)絡(luò)文件系統(tǒng)系統(tǒng)的縮寫(xiě),可以用于Linux和Linux之間傳遞文件,實(shí)現(xiàn)數(shù)據(jù)共享。安裝命令如下:</p><p>  apt-get install nfs-kernel-server</p><p><b>  2.修改配置文件</b></p><p&

24、gt;  打開(kāi)/etc/exports文件,增加mount -t nfs/NFS (rw,sync,no_root_squash,no_subtree_check)</p><p>  開(kāi)發(fā)板和其他 Linux 主機(jī)可以通過(guò)網(wǎng)絡(luò)訪問(wèn)/NFS 目錄。</p><p><b>  3.啟動(dòng)NFS</b></p><p>  sudo service

25、 rpcbind start </p><p>  sudo service nfs-kernel-server start</p><p><b>  掛載NFS文件系統(tǒng)</b></p><p>  mount -t nfs -o intr,nolock,rsize=1024,wsize=1024 192.168.1.86:/opt/ /mn

26、t</p><p><b>  交叉工具安裝</b></p><p>  1.在/usr/local/下建立交叉編譯器的安裝目錄arm:</p><p>  sudo  mkdir /usr/local/arm</p><p>  2.將下載的交叉編譯器包解壓到/usr/local/arm目錄下:</p&

27、gt;<p>  sudo tar jxvf cross-4.2.2-eabi.tar.bz2 -C /usr/local/arm/ </p><p>  3.解壓成功后,修改PATH環(huán)境變量:</p><p>  sudo vim  /etc/profile</p><p>  在文件為加入交叉編譯器arm-linux-所在的路徑

28、:</p><p>  export PATH=$PATH:/usr/local/arm/4.2.2-eabi/usr/bin</p><p>  4.更新一下配置文件/etc/profile:</p><p>  source /etc/profile</p><p><b>  軟件設(shè)計(jì)</b></p>

29、<p><b>  TCP/IP協(xié)議</b></p><p><b>  網(wǎng)絡(luò)模型</b></p><p>  圖 3-1-1 網(wǎng)絡(luò)模型</p><p>  如圖3-1-1所示,在TCP/IP協(xié)議中,將互聯(lián)網(wǎng)劃分成為應(yīng)用層、傳輸層、網(wǎng)絡(luò)層、網(wǎng)絡(luò)接口層,其中網(wǎng)絡(luò)接口層的主要功能是提供二進(jìn)制傳輸和介質(zhì)訪問(wèn)的功能;網(wǎng)

30、絡(luò)層負(fù)責(zé)IP尋址和路由,其中要考慮路由算法,擁塞控制等問(wèn)題;傳輸層負(fù)責(zé)應(yīng)用程序之間的連接;</p><p><b>  TCP連接</b></p><p>  TCP IP一般通過(guò)internet串行線路協(xié)議SLIP或點(diǎn)對(duì)點(diǎn)協(xié)議PPP在串行線上進(jìn)行數(shù)據(jù)傳送。TCP/IP協(xié)議的基本傳輸單位是數(shù)據(jù)包 (datagram)。TCP協(xié)議負(fù)責(zé)把數(shù)據(jù)分成若干個(gè)數(shù)據(jù)包/段,并給每個(gè)

31、數(shù)據(jù)包加上包頭,IP協(xié)議在每個(gè)包頭上再加上接收端主機(jī)地址,這樣數(shù)據(jù)找到自己要去的地方。如果傳輸過(guò)程中出現(xiàn)數(shù)據(jù)丟失、數(shù)據(jù)失真等情況,TCP協(xié)議會(huì)自動(dòng)要求數(shù)據(jù)重新傳輸并重新組包。TCP協(xié)議保證數(shù)據(jù)傳輸?shù)馁|(zhì)量,IP協(xié)議保證數(shù)據(jù)的傳輸。數(shù)據(jù)在傳輸時(shí)每通過(guò)一層就要在數(shù)據(jù)上加個(gè)包頭,其中數(shù)據(jù)供接收端同一層協(xié)議使用,而在接收端每經(jīng)過(guò)一層要把用過(guò)的包頭去掉,這樣來(lái)保證傳輸數(shù)據(jù)的格式完全一致。TCP/IP協(xié)議需要針對(duì)不同的網(wǎng)絡(luò)進(jìn)行不同的設(shè)置,且每個(gè)節(jié)點(diǎn)一

32、般需要一個(gè)“IP地址”、一個(gè)“子網(wǎng)掩碼”、一個(gè)“默認(rèn)網(wǎng)關(guān)”。不過(guò)可以通過(guò)動(dòng)態(tài)主機(jī)配置協(xié)議(DHCP),給客戶端自動(dòng)分配一個(gè)IP地址,這樣避免了出錯(cuò)也簡(jiǎn)化了TCP/IP協(xié)議的設(shè)置。</p><p>  如圖3-1-2所示,TCP是通過(guò)3次握手建立的:</p><p>  客戶端給服務(wù)器發(fā)送SYN(syn = j)包,進(jìn)入SYN_SEND狀態(tài)。</p><p>  服務(wù)

33、器接收到SYNC包,確認(rèn)客戶的SYN(ack = j+1),同時(shí)自己也發(fā)送一個(gè)SYN包(syn = k),把它倆都發(fā)送出去,服務(wù)器進(jìn)入SYN_SEND狀態(tài)。</p><p>  客戶端收到服務(wù)器的SYN+ACK包,向服務(wù)器發(fā)送ACK(ack = k+1),客戶端和服務(wù)器都進(jìn)入ESTABLISHED狀態(tài)。此時(shí),連接已經(jīng)建立完畢,可以相互發(fā)送發(fā)送消息。</p><p>  圖 3-1-2 三次

34、握手示意圖</p><p><b>  多線程編程</b></p><p>  進(jìn)程是系統(tǒng)中程序執(zhí)行和資源分配的基本單位。每個(gè)進(jìn)程都擁有自己的數(shù)據(jù)段、代碼段和堆棧段,這就造成了進(jìn)程在進(jìn)行切換等操作時(shí)都需要有比較復(fù)雜的上下文切換等動(dòng)作。為了進(jìn)一步減少處理機(jī)的空轉(zhuǎn)時(shí)間,支持多處理器以及減少上下文切換開(kāi)銷(xiāo),進(jìn)程在演化中出現(xiàn)了另一個(gè)概念——線程。它是進(jìn)程內(nèi)獨(dú)立的一條運(yùn)行路線,

35、處理器調(diào)度的最小單元,也可以稱為輕量級(jí)進(jìn)程。線程可以對(duì)進(jìn)程的內(nèi)存空間和資源進(jìn)行訪問(wèn),并與同一進(jìn)程中的其他線程共享。因此,線程的上下文切換的開(kāi)銷(xiāo)比創(chuàng)建進(jìn)程小很多。</p><p>  同進(jìn)程一樣,線程也將相關(guān)的執(zhí)行狀態(tài)和存儲(chǔ)變量放在線程控制表內(nèi)。一個(gè)進(jìn)程可以有多個(gè)線程,也就是有多個(gè)線程控制表及堆棧寄存器,但卻共享一個(gè)用戶地址空間。要注意的是,由于線程共享了進(jìn)程的資源和地址空間,因此,任何線程對(duì)系統(tǒng)資源的操作都會(huì)給其

36、他線程帶來(lái)影響。由此可知,多線程中的同步是非常重要的問(wèn)題,以下是線程同步用到的一些方法:</p><p><b>  互斥鎖</b></p><p>  互斥鎖是用一種簡(jiǎn)單的加鎖方法來(lái)控制對(duì)共享資源的原子操作。這個(gè)互斥鎖只有兩種狀態(tài),也就是上鎖和解鎖,可以把互斥鎖看作某種意義上的全局變量。在同一時(shí)刻只能有一個(gè)線程掌握某個(gè)互斥鎖,擁有上鎖狀態(tài)的線程能夠?qū)蚕碣Y源進(jìn)行操作

37、。若其他線程希望上鎖一個(gè)已經(jīng)被上鎖的互斥鎖,則該線程就會(huì)掛起,直到上鎖的線程釋放掉互斥鎖為止。可以說(shuō),這把互斥鎖保證讓每個(gè)線程對(duì)共享資源按順序進(jìn)行原子操作。</p><p>  互斥鎖可以分為快速互斥鎖、遞歸互斥鎖和檢錯(cuò)互斥鎖。這三種鎖的區(qū)別主要在于其他未占有互斥鎖的線程在希望得到互斥鎖時(shí)是否需要阻塞等待。快速鎖是指調(diào)用線程會(huì)阻塞直至擁有互斥鎖的線程解鎖為止。遞歸互斥鎖能夠成功地返回,并且增加調(diào)用線程在互斥上加鎖

38、的次數(shù),而檢錯(cuò)互斥鎖則為快速互斥鎖的非阻塞版本,它會(huì)立即返回并返回一個(gè)錯(cuò)誤信息。</p><p>  互斥鎖機(jī)制主要包括下面的基本函數(shù):</p><p>  互斥鎖初始化:pthread_mutex_init()</p><p>  互斥鎖上鎖:pthread_mutex_lock()</p><p>  互斥鎖判斷上鎖:pthread_mu

39、tex_trylock()</p><p>  互斥鎖解鎖:pthread_mutex_unlock()</p><p>  消除互斥鎖:pthread_mutex_destroy()</p><p><b>  信號(hào)量</b></p><p>  信號(hào)量也就是操作系統(tǒng)中所用到的PV原子操作,它廣泛用于進(jìn)程或線程間的同步

40、與互斥。信號(hào)量本質(zhì)上是一個(gè)非負(fù)的整數(shù)計(jì)數(shù)器,它被用來(lái)控制對(duì)公共資源的訪問(wèn)。</p><p>  PV原子操作是對(duì)整數(shù)計(jì)數(shù)器信號(hào)量sem的操作。一次P操作使sem減一,而一次V操作使sem加一。進(jìn)程(或線程)根據(jù)信號(hào)量的值來(lái)判斷是否對(duì)公共資源具有訪問(wèn)權(quán)限。當(dāng)信號(hào)量sem的值大于等于零時(shí),該進(jìn)程(或線程)具有公共資源的訪問(wèn)權(quán)限;相反,當(dāng)信號(hào)量sem的值小于零時(shí),該進(jìn)程(或線程)就將阻塞直到信號(hào)量sem的值大于等于0為

41、止。</p><p>  信號(hào)量機(jī)制主要包括下面的基本函數(shù):</p><p>  創(chuàng)建信號(hào)量: sem_init()</p><p>  等待信號(hào)量:sem_wait()和sem_trywait()</p><p>  喚醒進(jìn)程:sem_post()</p><p>  獲取信號(hào)量: sem_getvalue()<

42、;/p><p>  刪除信號(hào)量: sem_destroy()</p><p>  Socket網(wǎng)絡(luò)編程模型</p><p>  在Linux中的網(wǎng)絡(luò)編程是通過(guò)socket接口來(lái)進(jìn)行的。socket是一種特殊的I/O接口,它也是一種文件描述符。它是一種常用的進(jìn)程之間通信機(jī)制,通過(guò)它不僅能實(shí)現(xiàn)本地機(jī)器上的進(jìn)程之間的通信,而且通過(guò)網(wǎng)絡(luò)能夠在不同機(jī)器上的進(jìn)程之間進(jìn)行通信。&l

43、t;/p><p>  源IP地址和目的IP地址以及源端口號(hào)和目的端口號(hào)的組合稱為套接字。其用于標(biāo)識(shí)客戶端請(qǐng)求的服務(wù)器和服務(wù),它是網(wǎng)絡(luò)通信過(guò)程中端點(diǎn)的抽象表示,包含進(jìn)行網(wǎng)絡(luò)通信必需的五種信息:連接使用的協(xié)議,本地主機(jī)的IP地址,本地進(jìn)程的協(xié)議端口,遠(yuǎn)地主機(jī)的IP地址,遠(yuǎn)地進(jìn)程的協(xié)議端口。</p><p>  TCP Server編程模型</p><p>  圖 3-2-1

44、 Server編程模型</p><p>  進(jìn)行版本協(xié)商(WSAStartup)</p><p>  創(chuàng)建一個(gè)套接字(socket())</p><p>  將套接字設(shè)為監(jiān)聽(tīng)狀態(tài)(listen())</p><p>  接受客戶端的連接請(qǐng)求(accept())</p><p>  發(fā)送或者接收數(shù)據(jù)(send()/rec

45、v())</p><p>  關(guān)閉套接字(close())</p><p>  TCP Client編程模型</p><p>  圖 3-2-2 Client編程模型</p><p>  進(jìn)行版本協(xié)商(WSAStartup)</p><p>  創(chuàng)建一個(gè)套接字(socket())</p><p&g

46、t;  連接到服務(wù)器(connect())</p><p>  發(fā)送或者接收函數(shù)(send()/recv())</p><p>  關(guān)閉套接字(close())</p><p><b>  程序設(shè)計(jì)</b></p><p><b>  主要內(nèi)容</b></p><p>  設(shè)

47、計(jì)TCP服務(wù)器程序,使用多線程實(shí)現(xiàn)”生產(chǎn)者-消費(fèi)者“模型,建立TCP服務(wù)器,響應(yīng)客戶端請(qǐng)求,發(fā)送客戶端指定的請(qǐng)求數(shù)據(jù)。</p><p>  1.創(chuàng)建線程持續(xù)產(chǎn)生數(shù)據(jù),數(shù)據(jù)包含(學(xué)號(hào),姓名(拼音),年齡,身高,體重,當(dāng)前系統(tǒng)時(shí)間(納秒數(shù))使用gettimeofday),可使用隊(duì)列/多維數(shù)組存儲(chǔ)數(shù)據(jù)。</p><p>  2.創(chuàng)建TCP服務(wù)器線程,響應(yīng)多個(gè)客戶端的連接,讀取隊(duì)列/數(shù)組,向客戶端

48、發(fā)送指定“學(xué)號(hào)”的數(shù)據(jù)。設(shè)計(jì)TCP服務(wù)器程序。</p><p>  3.創(chuàng)建TCP客戶端接收線程,連接服務(wù)器并請(qǐng)求指定“學(xué)號(hào)”的數(shù)據(jù),接收數(shù)據(jù)并存儲(chǔ)在文件中。要求存儲(chǔ)有意義的數(shù)據(jù),由于TCP是基于字節(jié)流的特征,需要做組包處理</p><p><b>  服務(wù)器端程序設(shè)計(jì)</b></p><p>  以下是服務(wù)器端程序的主函數(shù)部分,在主函數(shù)中,首

49、先創(chuàng)建了一個(gè)新的線程,然后按照網(wǎng)絡(luò)編程模型中服務(wù)器端的編程方法進(jìn)行了編程,詳細(xì)程序設(shè)計(jì)請(qǐng)參考附件1.</p><p>  void main(void)</p><p><b>  {</b></p><p>  /**************子線程相關(guān)*******************/</p><p>  pt

50、hread_t reader = -1; //read進(jìn)程的進(jìn)程號(hào)</p><p>  pthread_mutex_init(&mutex,NULL); //初始化 互斥鎖</p><p><b>  /*初始化數(shù)據(jù)*/</b></p><p>  int i = 0;</p><p>  for(i=0; i

51、<5; i++)</p><p><b>  {</b></p><p>  information[i].name = NAME[i];</p><p>  information[i].age = AGE[i];</p><p>  information[i].number = NUM[i];</p&g

52、t;<p>  information[i].high = HIGH[i];</p><p>  information[i].weigh = WIGHT[i];</p><p><b>  }</b></p><p>  /*創(chuàng)建線程,產(chǎn)生數(shù)據(jù)*/</p><p>  pthread_create(&a

53、mp;reader,NULL,(void*)&writer_function,NULL);</p><p>  /************主線程相關(guān)**********************/</p><p>  //創(chuàng)建socket</p><p>  nListenSock =socket(AF_INET,SOCK_STREAM,IPPROTO_TCP

54、);</p><p>  if(nListenSock<0)</p><p><b>  {</b></p><p>  printf("create listen socket error\n");</p><p><b>  return;</b></p>

55、<p><b>  }</b></p><p>  //設(shè)置socket選項(xiàng)</p><p>  int nValue=1;</p><p>  if(setsockopt(nListenSock,SOL_SOCKET,SO_REUSEADDR,(char*)&nValue,sizeof(int))<0)</p&

56、gt;<p><b>  {</b></p><p>  printf("set option SO_REUSEADDR fail!\n");</p><p>  close(nListenSock);</p><p><b>  return;</b></p><p&

57、gt;<b>  }</b></p><p><b>  //綁定</b></p><p>  struct sockaddr_in localAddr;</p><p>  memset(&localAddr,0x0,sizeof(localAddr));</p><p>  localA

58、ddr.sin_family =AF_INET;</p><p>  localAddr.sin_addr.s_addr =htonl(INADDR_ANY);</p><p>  localAddr.sin_port =htons(10000);</p><p>  if(bind(nListenSock,(struct sockaddr*)&localA

59、ddr,sizeof(struct sockaddr))<0)</p><p><b>  {</b></p><p>  printf("bind liste sock fail!\n");</p><p>  close(nListenSock);</p><p><b>  re

60、turn;</b></p><p><b>  }</b></p><p><b>  //監(jiān)聽(tīng)</b></p><p>  if(listen(nListenSock,5)<0)</p><p><b>  {</b></p><p>

61、;  printf("listen error!\n");</p><p>  close(nListenSock);</p><p><b>  return;</b></p><p><b>  }</b></p><p>  //創(chuàng)建客戶端的線程</p>&l

62、t;p>  int nSrvThreadId =1;</p><p>  nThreadFlag =1;</p><p>  if(pthread_create((pthread_t*)&nSrvThreadId,NULL,(void*)&serverThreadProc,NULL)<0)</p><p><b>  {<

63、/b></p><p>  printf("create server thread fail!\n");</p><p>  close(nListenSock);</p><p><b>  return;</b></p><p><b>  }</b></p&g

64、t;<p><b>  //等待退出</b></p><p><b>  while(1)</b></p><p><b>  {</b></p><p>  if(pthread_join(nSrvThreadId,NULL)!=0)</p><p><b

65、>  {</b></p><p><b>  return;</b></p><p><b>  }</b></p><p><b>  }</b></p><p><b>  }</b></p><p><

66、b>  客戶端程序設(shè)計(jì)</b></p><p>  以下是客戶端的程序設(shè)計(jì),代碼片段太過(guò)冗長(zhǎng),詳細(xì)的程序設(shè)計(jì)請(qǐng)參考附件2。</p><p>  void main(int argc, char** argv)</p><p><b>  {</b></p><p><b>  //創(chuàng)建套接字&

67、lt;/b></p><p>  int sockfd=-1;</p><p>  sockfd =socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);</p><p>  if(sockfd<0)</p><p><b>  {</b></p><p> 

68、 printf("socket create error\n");</p><p><b>  return;</b></p><p><b>  }</b></p><p><b>  ......</b></p><p><b>  //建立

69、連接</b></p><p>  while(1) //建立鏈接</p><p><b>  {</b></p><p>  if(connect(sockfd,</p><p>  (struct sockaddr*)&serverAddr,</p><p>  size

70、of(serverAddr))==0)</p><p><b>  {</b></p><p>  printf("connected\n");</p><p><b>  break;</b></p><p><b>  }</b></p>

71、<p><b>  sleep(1);</b></p><p><b>  }</b></p><p><b>  ......</b></p><p><b>  //創(chuàng)建交互進(jìn)程</b></p><p>  pthread_t ipt_id;

72、</p><p>  if(pthread_create((pthread_t *)&ipt_id,NULL,(void*)&input,NULL)<0)</p><p><b>  {</b></p><p>  printf("create input thread fail!\n");</p

73、><p>  close(ipt_id);</p><p><b>  return;</b></p><p><b>  }</b></p><p><b>  ......</b></p><p><b>  }</b></p

74、><p><b>  綜合測(cè)試</b></p><p><b>  功能測(cè)試 </b></p><p>  1.運(yùn)行服務(wù)器端程序,處于監(jiān)聽(tīng)狀態(tài),等待客戶端來(lái)連接,當(dāng)有客戶端連接上,輸出連接的客戶端的信息。</p><p>  圖 4-1-1 服務(wù)器運(yùn)行</p><p>  2.運(yùn)

75、行客戶端程序,等待用戶輸入要從數(shù)據(jù)庫(kù)中讀取的信息編號(hào),當(dāng)用戶輸入要讀取的信息標(biāo)號(hào)的時(shí)候,服務(wù)器響應(yīng)客戶端的請(qǐng)求,回復(fù)信息。</p><p>  圖 4-1-2 客戶端運(yùn)行</p><p>  3.在當(dāng)前目錄下生成一個(gè).txt文件,內(nèi)部包含客戶端請(qǐng)求的信息。</p><p>  圖 4-1-3 生成文件</p><p>  4.打開(kāi)文件,內(nèi)部為

76、請(qǐng)求的信息。</p><p>  圖 4-1-4 文件內(nèi)容</p><p><b>  結(jié)論</b></p><p>  本次課程設(shè)計(jì)的內(nèi)容是基于Linux操作系統(tǒng)的多線程網(wǎng)絡(luò)編程,實(shí)現(xiàn)的功能是“生產(chǎn)者”,“消費(fèi)者”模型,建立TCP服務(wù)器,響應(yīng)客戶端請(qǐng)求,并發(fā)送客戶端請(qǐng)求的數(shù)據(jù)。在程序的設(shè)計(jì)過(guò)程中采用了多線程的編程方式,顯著提高了程序運(yùn)行的效率

77、。</p><p>  客戶端與服務(wù)器通過(guò)TCP方式建立連接,使用的通訊函數(shù)接口為套接字,套接字在網(wǎng)絡(luò)編程中有著舉足輕重的地位。通過(guò)本次課程設(shè)計(jì),我們創(chuàng)建TCP服務(wù)器線程,響應(yīng)多個(gè)客戶端的連接,讀取隊(duì)列/數(shù)組,向客戶端發(fā)送指定“學(xué)號(hào)”的數(shù)據(jù);創(chuàng)建TCP客戶端接收線程,連接服務(wù)器并請(qǐng)求指定“學(xué)號(hào)”的數(shù)據(jù),接收數(shù)據(jù)并存儲(chǔ)在文件中;在實(shí)現(xiàn)的這個(gè)過(guò)程中,利用數(shù)據(jù)結(jié)構(gòu)中的隊(duì)列構(gòu)造了數(shù)據(jù)表,方便程序訪問(wèn),同時(shí),也方便服務(wù)器端

78、對(duì)數(shù)據(jù)的管理。</p><p>  通過(guò)本次課程設(shè)計(jì),掌握了Linux下的編程模式和編程方法,熟悉了Linux的基本操作;同時(shí),掌握了開(kāi)發(fā)環(huán)境的搭建,常用的軟件服務(wù)的安裝,鍛煉了實(shí)際的工程能力;通過(guò)多線程編程方法,理解了線程和進(jìn)程的區(qū)別和聯(lián)系,掌握了創(chuàng)建線程和注銷(xiāo)線程的方法;通過(guò)對(duì)套接字的使用,掌握了在Linux下基于套接字的網(wǎng)絡(luò)編程,理解了Linux下套接字編程在服務(wù)器端和客戶端的編程流程,了解了網(wǎng)絡(luò)模型,提高

79、了解決問(wèn)題的能力。</p><p><b>  參考文獻(xiàn)</b></p><p>  范展源.深度實(shí)踐嵌入式Linux系統(tǒng)移植.北京:機(jī)械工業(yè)出版社,2015.5</p><p>  宋寶華.Linux設(shè)備驅(qū)動(dòng)開(kāi)發(fā)詳解.北京:機(jī)械工業(yè)出版社,2015.7</p><p>  譚浩強(qiáng).C程序設(shè)計(jì).北京:清華大學(xué)出版社,20

80、10.6</p><p>  陳文智.嵌入式系統(tǒng)設(shè)計(jì)與原理.北京:清華大學(xué)出版社,2011.5</p><p>  宋敬彬.Liunx網(wǎng)絡(luò)編程.北京:清華大學(xué)出版社,2010.6</p><p>  附錄一 服務(wù)器端程序</p><p>  /********************************************</p

81、><p>  文件名: server.c</p><p>  文件描述: 嵌入式課程設(shè)計(jì)程序</p><p>  完成日期:2017年9月8日</p><p><b>  作者:陳凱</b></p><p>  聯(lián)系方式:975500487@qq.com</p><p>  *

82、*******************************************/</p><p>  #include <stdio.h></p><p>  #include <sys/types.h></p><p>  #include <sys/socket.h></p><p>  #in

83、clude <arpa/inet.h></p><p>  #include <string.h></p><p>  #include <pthread.h> </p><p>  #include <stdlib.h></p><p>  #include<sys/time.h>

84、</p><p><b>  /*函數(shù)申明*/</b></p><p>  void writer_function(void);</p><p>  void serverThreadProc(void *);</p><p><b>  //鏈表結(jié)點(diǎn)結(jié)構(gòu)體</b></p><

85、p>  typedef struct _CLIENT_INFO_</p><p><b>  {</b></p><p>  charszClientIp[16];</p><p>  int nClientPort;</p><p>  intnClientSock;</p><

86、p>  struct_CLIENT_INFO_ *pNext;</p><p>  struct_CLIENT_INFO_ *pPre;</p><p>  }CLIENT_INFO;</p><p><b>  /*數(shù)據(jù)類型*/</b></p><p>  typedef struct datatype &l

87、t;/p><p><b>  {</b></p><p>  unsigned char number;</p><p>  unsigned char age;</p><p>  unsigned char high;</p><p>  unsigned char weigh;</p>

88、;<p>  long time;</p><p>  char *name;</p><p>  }Datatype;</p><p>  /****協(xié)議包結(jié)構(gòu)****/</p><p>  typedef struct pro_package</p><p><b>  {</b&

89、gt;</p><p>  char head; //開(kāi)始標(biāo)志為 設(shè)定為0x7E 1</p><p>  int lenth; //包的數(shù)據(jù)部分長(zhǎng)度 4</p><p>  unsigned char flag; //0 : cmd 1:data 1</p><p>  unsigned char sto

90、p; //0 stop 1:send 1</p><p>  unsigned char num; //標(biāo)明發(fā)送信息 1</p><p>  unsigned char data[200]; //數(shù)據(jù)部分 </p><p>  }Pro_package;</p><p><b>  /*創(chuàng)建緩存區(qū)*/&

91、lt;/b></p><p>  typedef struct queue</p><p><b>  {</b></p><p>  Datatype buffer[5]; </p><p>  int b_tail;</p><p>  int b_head;</p>&l

92、t;p><b>  }queue; </b></p><p><b>  /*初始化隊(duì)列*/</b></p><p>  queue Queue = </p><p><b>  {</b></p><p>  .b_tail = 0,</p><p&

93、gt;  .b_head = 0,</p><p><b>  };</b></p><p><b>  /*數(shù)據(jù)初始化*/</b></p><p>  char *NAME[5] = {"wuhao", "chenkai","liumenglin","

94、liujin","liufeng"};</p><p>  unsigned char AGE[5] = {20,21,22,23,24};</p><p>  unsigned char NUM[5] = {1,2,3,4,5};</p><p>  unsigned char HIGH[5] = {175,174,173,175,1

95、65};</p><p>  unsigned char WIGHT[5] = {58, 55, 62, 63, 50};</p><p>  Datatype information[5];</p><p>  /****全局變量***/</p><p>  int nListenSock =-1; //server lisen socke

96、t</p><p>  int nThreadFlag =0; // thread start/stop flag</p><p>  CLIENT_INFO *pClientHead=NULL; //client list header</p><p>  struct timeval sys_time;</p><p>  pthrea

97、d_mutex_t mutex;</p><p>  int buffer_has_item=0;</p><p><b>  //主函數(shù)</b></p><p>  void main(void)</p><p><b>  {</b></p><p>  /*******

98、*******子線程相關(guān)*******************/</p><p>  pthread_t reader = -1; //read進(jìn)程的進(jìn)程號(hào)</p><p>  pthread_mutex_init(&mutex,NULL); //初始化 互斥鎖</p><p><b>  /*初始化數(shù)據(jù)*/</b></p>

99、;<p>  int i = 0;</p><p>  for(i=0; i<5; i++)</p><p><b>  {</b></p><p>  information[i].name = NAME[i];</p><p>  information[i].age = AGE[i];</

100、p><p>  information[i].number = NUM[i];</p><p>  information[i].high = HIGH[i];</p><p>  information[i].weigh = WIGHT[i];</p><p><b>  }</b></p><p&g

101、t;  /*創(chuàng)建線程,產(chǎn)生數(shù)據(jù)*/</p><p>  pthread_create(&reader,NULL,(void*)&writer_function,NULL);</p><p>  /************主線程相關(guān)**********************/</p><p>  //創(chuàng)建socket</p><p

102、>  nListenSock =socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);</p><p>  if(nListenSock<0)</p><p><b>  {</b></p><p>  printf("create listen socket error\n");<

103、;/p><p><b>  return;</b></p><p><b>  }</b></p><p>  //設(shè)置socket選項(xiàng)</p><p>  int nValue=1;</p><p>  if(setsockopt(nListenSock,SOL_SOCKET,

104、</p><p>  SO_REUSEADDR,(char*)&nValue,sizeof(int))<0)</p><p><b>  {</b></p><p>  printf("set option SO_REUSEADDR fail!\n");</p><p>  close(

105、nListenSock);</p><p><b>  return;</b></p><p><b>  }</b></p><p><b>  //綁定</b></p><p>  struct sockaddr_in localAddr;</p><p

106、>  memset(&localAddr,0x0,sizeof(localAddr));</p><p>  localAddr.sin_family =AF_INET;</p><p>  localAddr.sin_addr.s_addr =htonl(INADDR_ANY);</p><p>  localAddr.sin_port =htons

107、(10000);</p><p>  if(bind(nListenSock,(struct sockaddr*)&localAddr,sizeof(struct sockaddr))<0)</p><p><b>  {</b></p><p>  printf("bind liste sock fail!\n&quo

108、t;);</p><p>  close(nListenSock);</p><p><b>  return;</b></p><p><b>  }</b></p><p><b>  //監(jiān)聽(tīng)</b></p><p>  if(listen(nLi

109、stenSock,5)<0)</p><p><b>  {</b></p><p>  printf("listen error!\n");</p><p>  close(nListenSock);</p><p><b>  return;</b></p>

110、<p><b>  }</b></p><p>  //創(chuàng)建客戶端的線程</p><p>  int nSrvThreadId =1;</p><p>  nThreadFlag =1;</p><p>  if(pthread_create((pthread_t*)&nSrvThreadId,NU

111、LL,(void*)&serverThreadProc,NULL)<0)</p><p><b>  {</b></p><p>  printf("create server thread fail!\n");</p><p>  close(nListenSock);</p><p>

112、;<b>  return;</b></p><p><b>  }</b></p><p><b>  //等待退出</b></p><p><b>  while(1)</b></p><p><b>  {</b></p&

113、gt;<p>  if(pthread_join(nSrvThreadId,NULL)!=0)</p><p><b>  {</b></p><p><b>  return;</b></p><p><b>  }</b></p><p><b> 

114、 }</b></p><p><b>  }</b></p><p>  /*處理客戶端函數(shù)*/</p><p>  void serverThreadProc(void *pPram)</p><p><b>  {</b></p><p>  int nMa

115、xFd;</p><p>  fd_set rset,allset;</p><p>  struct timeval timeOut={0,20*1000};</p><p>  FD_ZERO(&allset);</p><p>  FD_SET(nListenSock,&allset);</p><p

116、>  nMaxFd =nListenSock;</p><p>  CLIENT_INFO *pTcpClient;</p><p>  int nSelectR;</p><p>  struct sockaddr_in clientAddr;</p><p>  CLIENT_INFO *pTempClient;</p>

117、<p>  unsigned char ucRcvBuf[100];</p><p>  int nAddrSize =sizeof(clientAddr);</p><p>  Pro_package package; //定義包結(jié)構(gòu)</p><p>  unsigned char send_buffer[200]; //發(fā)送緩存</p&g

118、t;<p>  int verify_flag = 0;</p><p>  while(1) //while 循環(huán)</p><p><b>  {</b></p><p>  rset =allset;</p><p>  nSelectR =select(nMaxFd+1,&rset,NULL

119、,NULL,&timeOut);</p><p>  if(nSelectR==-1) //若發(fā)生錯(cuò)誤</p><p><b>  {</b></p><p><b>  continue;</b></p><p><b>  }</b></p><

120、;p>  else if(nSelectR==0) //超時(shí)</p><p><b>  {</b></p><p><b>  continue;</b></p><p><b>  }</b></p><p>  if(FD_ISSET(nListenSock,&a

121、mp;rset)) // 檢查nListenSock是否在套接字集合中</p><p><b>  {</b></p><p>  printf("accept client!\n");</p><p>  int nConnectSock =accept(nListenSock,(struct sockaddr*)&a

122、mp;clientAddr,&nAddrSize);</p><p>  if(nConnectSock==-1)</p><p><b>  {</b></p><p>  printf("nConnectSock -1\n");</p><p><b>  continue;&l

123、t;/b></p><p><b>  }</b></p><p>  //保存客戶端的信息</p><p>  pTcpClient =(CLIENT_INFO*)malloc(sizeof(CLIENT_INFO));</p><p>  pTcpClient->nClientSock =nConnect

124、Sock;</p><p>  pTcpClient->nClientPort =ntohs(clientAddr.sin_port);</p><p>  strcpy(pTcpClient->szClientIp,inet_ntoa(clientAddr.sin_addr));</p><p>  pTcpClient->pNext =NULL

125、;</p><p>  pTcpClient->pPre =NULL;</p><p>  printf("client connected,ip:%s,port:%d\n",</p><p>  pTcpClient->szClientIp,</p><p>  pTcpClient->nClientP

126、ort);</p><p>  if(pClientHead==NULL)</p><p><b>  {</b></p><p>  pClientHead= pTcpClient;</p><p><b>  }</b></p><p><b>  else&l

127、t;/b></p><p><b>  {</b></p><p>  pTempClient =pClientHead;</p><p>  while(pTempClient->pNext!=NULL)</p><p><b>  {</b></p><p>

128、  pTempClient =pTempClient->pNext;</p><p><b>  }</b></p><p>  pTempClient->pNext =pTcpClient;</p><p>  pTcpClient->pPre =pTempClient;</p><p><b

129、>  }</b></p><p>  //update fd set</p><p>  FD_SET(nConnectSock,&allset);</p><p>  if(nConnectSock>nMaxFd)</p><p><b>  {</b></p><p

130、>  nMaxFd =nConnectSock;</p><p><b>  }</b></p><p><b>  }</b></p><p>  else //對(duì)客戶端的服務(wù)</p><p><b>  {</b></p><p>  //f

131、ind the client </p><p>  pTcpClient =pClientHead;</p><p>  while(pTcpClient!=NULL)</p><p><b>  {</b></p><p>  int nRcvSock =pTcpClient->nClientSock;</

132、p><p>  if(FD_ISSET(nRcvSock,&rset)==0)</p><p><b>  {</b></p><p>  pTcpClient =pTcpClient->pNext;</p><p><b>  continue;</b></p><p

溫馨提示

  • 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ù)僅提供信息存儲(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)論