版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
南京工程學(xué)院畢業(yè)設(shè)計(jì)說(shuō)明書(論文)南京工程學(xué)院畢業(yè)設(shè)計(jì)說(shuō)明書(論文)院系:通信工程學(xué)院專業(yè):通信工程(電力通信)題目:基于Linux平臺(tái)的網(wǎng)絡(luò)聊天軟件的設(shè)計(jì)與研究指導(dǎo)者: 評(píng)閱者:2015年6月南京DesignandimplementationasoftwarewhichcancommunicateonLinuxADissertationSubmittedtoNanjingInstituteofTechnologyADissertationSubmittedtoNanjingInstituteofTechnologyFortheAcademicDegreeofBachelorofScienceSupervisedbyLecturerLeiTangCollegeofNanjingInstituteofTechnologyJune2015摘要Linuxkernel由于其代碼的開源及獲取方便等優(yōu)點(diǎn),越來(lái)越受到廣大技術(shù)人員的青睞。Linux系統(tǒng)提供了完整的內(nèi)核源代碼,在此代碼的基礎(chǔ)上可以進(jìn)行自定義,從而打造屬于自己的“專屬”系統(tǒng)。Socket通訊使用C/S模型,Socket上TCP/IP網(wǎng)絡(luò)應(yīng)用程序接口(API),提供了很多函數(shù)方開發(fā)人員利用。Socket通訊有兩種傳輸協(xié)議:TCP協(xié)議和UDP協(xié)議,TCP協(xié)議是面向連接的,傳輸可靠的;UDP是無(wú)連接的,傳輸不可靠的,因此本設(shè)計(jì)中選用TCP。進(jìn)程和線程是不同的,進(jìn)程擁有自身的程序映像和地址空間,是內(nèi)核調(diào)度的基本單元,每個(gè)單獨(dú)的進(jìn)程都有自己的代碼段、數(shù)據(jù)段以及堆棧,它們使用自己的虛擬地址空間,多個(gè)進(jìn)程間互不影響。而線程沒(méi)有自己獨(dú)立的地址空間,創(chuàng)建出來(lái)的新線程和創(chuàng)建它的進(jìn)程共享一個(gè)虛擬地址空間。這些知識(shí)點(diǎn)將在論文中詳細(xì)介紹。本設(shè)計(jì)主要對(duì)服務(wù)端和客戶端程序進(jìn)行編寫并對(duì)其進(jìn)行調(diào)試,從而實(shí)現(xiàn)客戶端和服務(wù)端之間的通信??偟膩?lái)講,本設(shè)計(jì)使用C語(yǔ)言開發(fā),通過(guò)Socket建立連接,并創(chuàng)建多個(gè)線程的實(shí)現(xiàn)多任務(wù)。關(guān)鍵詞:Linux內(nèi)核;socket;進(jìn)程;線程;多任務(wù)AbstractBecauseofmeritinopeningofsourcecodeandgettingconvenient,linuxkernelbecomemoreandmorepopularamongtheprogrammers.LinuxprovidesintegratedsourcecodeofLinux-kernel,peoplecanmakespecialsystembelongstothemselvesbasedonthesourcecode. SocketcommunicationuseC/Smodel,andtheAPIofTCP/IPonitprovidesplentyoffunctionsforprogrammerstouse.Socketcommunicationhastwotransferprotocols:TCPandUDP;TCPisconnectionandreliable,butUDPisconnectionlessandunreliable.So,wechooseTCPinthisdesign. Processisdifferentfromthread.Processhasitproceduremapandaddressspace,it‘sbasicunitofthekernelscheduling,eachsingleprocesshasitsowntext、dataandstack,theyusetheirsvirtualaddressspaceanddon’taffecteachother.Butthreaddoesn’thaveindependentaddressspace,itsharesthevirtualaddressspacewiththeprocesswhocreatesit.Thisknowledgewillbeintroducedinmythesis. Thisdesignrealizescommunicationbetweenclientandserverbydebugginginclientandserver’scode.Ingeneral,thisdesignusesClanguage,connectsbysocketandcreatesmultiplethreadstoimplementmultitasking.Keywords:Linux-kernel;socket;process;thread;multitask目錄第一章緒論 11.1設(shè)計(jì)背景 11.2應(yīng)用概述 21.3 為什么選擇Linux 41.4論文的主要工作 5第二章Linux編程常用工具 62.1嵌入式C語(yǔ)言 62.2GCC工具鏈 72.2.1GCC的用法 82.2.2調(diào)試和剖析選項(xiàng) 82.3GDB調(diào)試器 92.3.2GDB用法 92.3.1用gdb調(diào)試GCC程序 10第三章設(shè)計(jì)的實(shí)現(xiàn)及主要技術(shù) 133.1實(shí)現(xiàn)分析 133.1.1功能分析 133.1.2設(shè)計(jì)分析 133.1.3技術(shù)分析 143.3Socket(網(wǎng)絡(luò)套接字) 183.3.1編程步驟 193.3.2地址及順序地址 193.3.3鏈接函數(shù)說(shuō)明 223.4進(jìn)程 253.4.1進(jìn)程的概念 253.4.2進(jìn)程的內(nèi)存布局 263.4.3進(jìn)程生命周期 273.5多線程 283.5.1線程的概念 283.5.2進(jìn)程和線程的關(guān)系及優(yōu)缺點(diǎn) 283.5.3數(shù)據(jù)類型及其用法 303.6線程同步 313.6.1概念 313.6.2線程同步的幾種方法:信號(hào)量、自旋鎖、互斥量 323.6.3互斥量的使用 323.7ncurrses字符界面 333.7.1ncurses簡(jiǎn)介 333.7.2ncurses常用函數(shù)介紹 34第四章設(shè)計(jì)的編程實(shí)現(xiàn) 364.1聊天室Socket編程連接 364.2聊天室程序設(shè)計(jì)及界面設(shè)計(jì) 384.2.1服務(wù)器 384.2.2客戶端 384.2.3客戶端主體界面及功能展示 41第五章總結(jié)與展望 445.1全篇總結(jié) 445.2設(shè)計(jì)中遇到的問(wèn)題及解決辦法 445.3設(shè)計(jì)有待改進(jìn)的地方 46致謝 47參考文獻(xiàn) 48第48頁(yè)第一章緒論1.1設(shè)計(jì)背景 Linux是兼容POSIX的U-like操作系統(tǒng),大多數(shù)重要的UNIX工具、應(yīng)用程序和網(wǎng)絡(luò)協(xié)議都能在其上運(yùn)行。Linux系統(tǒng)目前已經(jīng)得到了很廣泛的應(yīng)用。它是由芬蘭人LinuxTorvalds開發(fā)的。 Linux最初是為intel_x86平臺(tái)開發(fā)的免費(fèi)操作系統(tǒng),從那時(shí)開始Linux就被陸續(xù)移植到其他硬件工作平臺(tái)。在服務(wù)器方面Linux操作系統(tǒng)一直處于領(lǐng)先地位,比如大型機(jī)和超級(jí)計(jì)算機(jī),但在桌面用戶市場(chǎng)只占到了1.5%。Linux也可以運(yùn)行在嵌入式設(shè)備之中,這些設(shè)備主要包括移動(dòng)電話、平板電腦、網(wǎng)絡(luò)路由、自動(dòng)控制設(shè)備和電視機(jī)等等。Android是Linux操作系統(tǒng)在平板和智能電話中用的最為廣泛的一款操作系統(tǒng)構(gòu)建與LinuxKernel上層。 基于代碼開源的優(yōu)勢(shì),linux具有強(qiáng)大市場(chǎng)競(jìng)爭(zhēng)力。只要想獲得源碼,便可從官方網(wǎng)站上獲取LinuxKernel源代碼,有了源代碼之后就可以自定義操作系統(tǒng)了。在此基礎(chǔ)上安裝自己的應(yīng)用軟件,至此一個(gè)完整的屬于自己的操作系統(tǒng)就誕生了。通常將這樣安裝所獲得的系統(tǒng)稱為L(zhǎng)inux系統(tǒng),這是因?yàn)樗牟恢挂粋€(gè)內(nèi)核。 提及Linux,那就得提到GNU和Unix。1983年9月27號(hào),RichardStallman希望開發(fā)一套完整的開放源碼操作系統(tǒng)以取代Unix,從而誕生了GNU。1985年,發(fā)表GNU宣言;1989年,發(fā)表GNU(GNUGneralPublicLicense,GPL);GPL的開源思想使得我們的學(xué)習(xí)之路順暢了許多。GPL保障了Linux不僅僅是當(dāng)下自由可用,而且今后經(jīng)過(guò)任何修改后還是自由可用的,這點(diǎn)充分體現(xiàn)了Stallman的初衷。 Unix是于1969年在美國(guó)AT&T公司貝爾實(shí)驗(yàn)室開發(fā)出來(lái)的具有多任務(wù),多用戶的操作系統(tǒng)。Unix的前身叫做Multics,由BELLLabs參與研發(fā),可是由于進(jìn)度緩慢,BellLabs不得不放棄了這個(gè)計(jì)劃。在這之后就由貝爾實(shí)驗(yàn)室的職員Kenthompson,DennisRitchie等繼續(xù)自行開發(fā)。在此之后的10年里,Unix在大型企業(yè)和學(xué)術(shù)界得到了普遍的應(yīng)用,其不斷擴(kuò)大的影響力終究還是引起了AT&T的關(guān)注,就這樣一場(chǎng)持續(xù)許久的版權(quán)官司開始了,直到AT&T將自己的貝爾實(shí)驗(yàn)室賣給Novell接手。最初的UNIX是用PDP-7匯編語(yǔ)言別寫的,但因?yàn)槠湓谙到y(tǒng)編程方面沒(méi)有太大優(yōu)勢(shì),于是Thompson和Ritchie兩人對(duì)其加以改造,并于1971年共同發(fā)明了C語(yǔ)言。1973年thompson和Ritchie用C語(yǔ)言重寫了UNIX,UNIX第三版就這樣問(wèn)世了。在當(dāng)時(shí),系統(tǒng)程序大多是由匯編語(yǔ)言編寫,thompson和Ritchie此舉是非常具有革新意義的。用C語(yǔ)言編寫的Unix代碼緊湊簡(jiǎn)潔、易讀、易修改,為此后Unix的進(jìn)一步發(fā)展奠定了扎實(shí)的基礎(chǔ)。1.2應(yīng)用概述 嵌入式Linux是指運(yùn)行在分布式嵌入式設(shè)備上的Linux操作系統(tǒng),盡管“embedded”這一詞經(jīng)常用來(lái)討論內(nèi)核方面的知識(shí),但嵌入式應(yīng)用上的Linuxkernel并沒(méi)有什么特別之處。Linux內(nèi)核都是一樣的,只不過(guò)在不同的嵌入式設(shè)備上需要進(jìn)行不同的編譯步驟,從而讓Linux操作系統(tǒng)能夠在嵌入式設(shè)備上跑起來(lái)。嵌入式操作系統(tǒng)就是將Linux內(nèi)核和其他各種軟件編譯成的能夠運(yùn)行在嵌入式分布式設(shè)備中的系統(tǒng)。你得通過(guò)付款的方式獲得這特定的編譯工具,這些編譯工具通常指:交叉編譯器、調(diào)試器、項(xiàng)目管理軟件、引導(dǎo)鏡像等等,從而得到完整的一個(gè)運(yùn)行在嵌入式設(shè)備上的操作系統(tǒng)。隨著網(wǎng)絡(luò)的不斷發(fā)展,網(wǎng)絡(luò)在嵌入式系統(tǒng)中應(yīng)用十分廣泛,越來(lái)越多的嵌入式設(shè)備均采用Linux操作系統(tǒng)。傳統(tǒng)的嵌入式系統(tǒng)設(shè)備如:空間站、自動(dòng)系統(tǒng)、消費(fèi)電子系統(tǒng)、電話等等都使用Linux系統(tǒng),但這些嵌入式Linux系統(tǒng)大體上都相同,沒(méi)有什么新穎的特色。而且這些都沒(méi)有提及到系統(tǒng)的結(jié)構(gòu),Linux系統(tǒng)的結(jié)構(gòu)真正信息包括:大小、實(shí)時(shí)、網(wǎng)絡(luò)能力、和用戶的交互能力。Linux系統(tǒng)的選型非常重要,針對(duì)不同用戶的需求不一,Linux有很多發(fā)行版,在這之中又分很多類:桌面版、服務(wù)器版、企業(yè)版。桌面版針對(duì)的大多是普通用戶,有很好的桌面環(huán)境,比較適合于新手;服務(wù)器版多傾向與終端界面,沒(méi)有較好的桌面環(huán)境,在服務(wù)器開發(fā)方面有很大優(yōu)勢(shì);企業(yè)版則面向的大多是大型企業(yè),對(duì)信息安全,網(wǎng)絡(luò)穩(wěn)定方面都很高。Linux由于其公開的源碼及免費(fèi)的操作系統(tǒng),在Linuxkernel的代碼獲取及相關(guān)構(gòu)建工具沒(méi)有任何限制。因此對(duì)基于Linux平臺(tái)的Socket網(wǎng)絡(luò)編程的研究就顯得很重要,下圖1.1為其C/S簡(jiǎn)易模式圖和圖1.2詳細(xì)模式圖:圖1.1C/S簡(jiǎn)易模式圖圖1.2C/S詳細(xì)模式圖編寫Socket的server和client端程序,雙方通過(guò)socket建立連接,從而完成進(jìn)一步的通信。為什么選擇Linux1.代碼的質(zhì)量和可依賴性。質(zhì)量和可依賴性是衡量代碼優(yōu)劣的重要標(biāo)準(zhǔn)。盡管在“qualitycode”眾說(shuō)紛紜,但是大多數(shù)編程人員所期望的都有如下幾點(diǎn):(1)模塊化:每一個(gè)功能都寫成一個(gè)模塊,這樣不僅易于讀寫,更加方便以后的移植;(2)可讀性:一段代碼應(yīng)該能讓別人看的下去,這里包括變量的定義,盡量取有意義的變量名,避免inti,j這樣的定義;一段雜亂的讓人看一眼就不想往下看的代碼一定是不好的,不管功能有多牛。;(3)可擴(kuò)展性:在增加新的功能時(shí),不要對(duì)原來(lái)的代碼進(jìn)行大篇幅的修改,而是只要添加對(duì)應(yīng)的功能即可;(4)可配置性:可以選擇對(duì)應(yīng)的功能特色進(jìn)行編譯,不要的就不編譯,從而生成的程序適合自己的使用。但是配置的過(guò)程應(yīng)該盡量簡(jiǎn)單人性化。2.TCP/IP協(xié)議由網(wǎng)絡(luò)層的IP協(xié)議和傳輸層的TCP協(xié)議組成,是Internet最基本的協(xié)議、是Internet國(guó)際互聯(lián)網(wǎng)絡(luò)的基礎(chǔ)。Socket通信所采用的協(xié)議分為面向連接(TCP)和非面向連接(UDP)的兩種,但由于UDP效率較高但是傳輸不可靠,不能勝任復(fù)雜的網(wǎng)絡(luò)環(huán)境,不得不通過(guò)超時(shí)和重傳等手段來(lái)實(shí)現(xiàn)較高的可靠性;然而TCP在數(shù)據(jù)傳輸方面提供了完全的可靠性,因此選用TCP/IP協(xié)議更加可靠些。3.代碼的可獲得性。Linuxkernel源碼及所有的開發(fā)和編譯工具是很方便從網(wǎng)絡(luò)上獲取的。Linux中最重要的部分Linuxkernel分布在GPL下。其他的代碼也分布在相同的證書下,如BSD等。構(gòu)成Linux的大部分代碼都是沒(méi)有限制的。當(dāng)源碼的訪問(wèn)受限時(shí),開放自由軟件組織就會(huì)尋找新版本的源碼包代替原有的代碼。正是由于這一特性,Linux受到很多電話制造商的青睞,他們將其移植到自己產(chǎn)品中,稍作修改優(yōu)化使其適合自己的產(chǎn)品。4.硬件支持。Linux支持不同種類的硬件平臺(tái)和設(shè)備,盡管有些驅(qū)動(dòng)暫不支持Linux系統(tǒng),但是對(duì)此有很大的期待。因?yàn)楹芏囹?qū)動(dòng)都由Linuxshequ維護(hù)著,你可以毫無(wú)顧忌的使用這些驅(qū)動(dòng)。各種硬件協(xié)同工作,使你的工作更加順暢。你希望在你自己電腦上編寫的程序能夠在另一架構(gòu)的操作系統(tǒng)上正常運(yùn)行,甚至有不同的設(shè)備驅(qū)動(dòng)運(yùn)行在不同的系統(tǒng)架構(gòu)上。5.通信協(xié)議和軟件標(biāo)準(zhǔn)。Linux提供了廣泛的通信協(xié)議和標(biāo)準(zhǔn)的軟件支持。這使得整合Frameworks及相關(guān)軟件到Linux上變得更加容易。同時(shí),Linux是U-like的,可以方便的將UNIX程序移植到Linux上。事實(shí)上,許多應(yīng)用被綁定在一些商用Unixes中,繼而被移植到Linux中。1.4論文的主要工作第一章:緒論,大體介紹Linux操作系統(tǒng)發(fā)展、應(yīng)用的現(xiàn)狀以及我們選擇Linux系統(tǒng)的原因;第二章:介紹Linux軟件開發(fā)中使用的編譯工具和調(diào)試工具及其簡(jiǎn)單的使用方法;第三章:介紹設(shè)計(jì)是怎樣實(shí)現(xiàn)的以及在實(shí)現(xiàn)的過(guò)程中用到了哪些關(guān)鍵技術(shù)并對(duì)這些關(guān)鍵技術(shù)作簡(jiǎn)要分析;第四章:介紹設(shè)計(jì)相關(guān)的主要代碼的實(shí)現(xiàn)過(guò)程,依次對(duì)服務(wù)器和客戶端主要流程進(jìn)行介紹,必要的功能展示;第五章:設(shè)計(jì)總結(jié)與展望第二章Linux編程常用工具2.1嵌入式C語(yǔ)言 C語(yǔ)言最初是由貝爾實(shí)驗(yàn)室的職員Thompson和Ritchie于1971年共同開發(fā)。其應(yīng)用場(chǎng)景很多,如:操作系統(tǒng):Linux;微控制器:汽車和航天飛機(jī);嵌入式處理器:電話和便攜式電子設(shè)備等;DSPProcesser:數(shù)字音頻圖像處理和TV系統(tǒng)等。程序的生成過(guò)程如圖2.1所示:圖2.1程序的生成過(guò)程C語(yǔ)言能夠在編程開發(fā)領(lǐng)域受到如此高的青睞,主要有以下幾個(gè)方面的原因:1.通用性。因而在跨平臺(tái)開發(fā)時(shí)非常方便,C語(yǔ)言的這一特性吸引著廣大編程愛(ài)好者;2.執(zhí)行速度快??梢灾付ň幾g選項(xiàng)從而省去中間過(guò)程,以進(jìn)一步提升程序的執(zhí)行效率。3.可移植性。由于各個(gè)平臺(tái)的差異,當(dāng)一個(gè)程序到不同平臺(tái)上,只需要從新編譯一下源代碼即可使用;4.發(fā)展快速。C語(yǔ)言發(fā)展較快。在上世紀(jì)80年代末期由AmericanNationalInstitude發(fā)布的ANSIC的C語(yǔ)言標(biāo)準(zhǔn)奠定了其發(fā)展的基石。2.2GCC工具鏈 GNU/Linux操作系統(tǒng)上往往使用gcc作為編譯工具。其不是一個(gè)單獨(dú)的程序,而是多個(gè)程序的組合,因而通常稱為toolchain(工具鏈)。GCC的全稱是GNUComplierCollection,是由GNUProject提供的支持多種編程語(yǔ)言的編譯器。GCC是GNUtoolchain中的重要組成部分,GCC作為一個(gè)工具和實(shí)例,在自由軟件的成長(zhǎng)過(guò)程中扮演著重要的作用。同年12月,GCC擴(kuò)展到能夠編譯C++,不久之后能夠支持的語(yǔ)言更多,如Objective-C、Objective-C++、Fortran、Java和Ada等等。 GCC被移植到多種架構(gòu)的處理器,并作為一種專業(yè)軟件開發(fā)工具配置于系統(tǒng)中。GCC同時(shí)也集成于大多數(shù)嵌入式平臺(tái),包括Symbian,AMCC等。作為GNU操作系統(tǒng)官方指定編譯器,GCC被其他U-like操作系統(tǒng)吸收采用,包括Linux和BSD家族。程序的編譯過(guò)程如圖2.2所示: 圖2.2源碼到可執(zhí)行文件的過(guò)程2.2.1GCC的用法 對(duì)于GCC的編譯選項(xiàng)只要掌握一些常用的選項(xiàng)就可以,其他多大100多種選項(xiàng)有些工程師可能一輩子也不會(huì)用到。 gcc基本用法: gcc[-Wall][-O1..3][-g][-oname]file... -Wall:打開所有警告項(xiàng)-O:設(shè)置優(yōu)化級(jí)別,O0表示關(guān)閉優(yōu)化功能-g:將調(diào)試信息編譯到目標(biāo)文件中-oname:指定輸出文件的名稱是namefile:被編譯(鏈接)的文件2.2.2調(diào)試和剖析選項(xiàng) gcc–g:以本機(jī)格式(stabs,COFF,XCOFF,orDWARF2)生成調(diào)試信息供gdb使用。 在大多數(shù)系統(tǒng)上,“-g”產(chǎn)生的調(diào)試信息只能供GDB使用,這種調(diào)試信息在gdb中能很好的工作,而在其他調(diào)試器上不是讀取不了就是調(diào)試器異常崩潰。如果你想指定調(diào)試信息的格式,可通過(guò)如下方式: -gstabs+、-gstabs、-gxcoff+、-gxcoff、-gvms gcc允許同時(shí)使用‘-g’、‘–o’,這種使用方法將會(huì)產(chǎn)生令你意想不到的效果:你定義的一些變量可能不存在、程序會(huì)跑飛掉、一些語(yǔ)句不會(huì)被執(zhí)行。不管是否提供可能的優(yōu)化輸出,但可以肯定的是,這將會(huì)產(chǎn)生一些bug。 但是這種方法使得你能夠在和最終產(chǎn)品盡可能相同的情況下對(duì)代碼進(jìn)行調(diào)試。應(yīng)當(dāng)注意,如果你同時(shí)使用這兩個(gè)編譯選項(xiàng),必須清楚所寫的某些有關(guān)代碼已經(jīng)在優(yōu)化時(shí)被GCC作了些改變。2.3GDB調(diào)試器GDB(GNUDebuger),是GNU操作系統(tǒng)的標(biāo)注調(diào)試器;。GDB作為GNU系統(tǒng)的一部分于1986年由RichardStallman編寫,是GPL下的自由軟件。使用者可以監(jiān)視和修改程序的內(nèi)部變量,甚至可以獨(dú)立地調(diào)用程式正常行為的函數(shù)。 GDB能對(duì)多種不同處理器架構(gòu)上運(yùn)行出錯(cuò)的應(yīng)用軟件排錯(cuò),這些處理器架構(gòu)包括:Alpha、ARM、AVR、H8/300、AlteraNios/NiosII、System/370、System390、X86及其64位擴(kuò)展。GDB明顯的限制是在他的運(yùn)用方面,沒(méi)有較親和的圖形界面,預(yù)設(shè)只有命令行界面可用。 Gdb是為了讓你能夠“看到”另一程序執(zhí)行時(shí)具體做了什么或者是另一程序崩潰時(shí)發(fā)生了什么 GDB可以做四件事情幫助你找到程序中的bug:?jiǎn)?dòng)你的程序,指定任何可能影響其行為的變量或函數(shù)等;使你的程序暫停(設(shè)置斷點(diǎn))或者指定特定的狀態(tài);當(dāng)你的程序終止時(shí),檢測(cè)發(fā)生了什么;改變你程序中的事情,這樣你就可以嘗試糾正一個(gè)bug的影響以便繼續(xù)往下找另一個(gè)bug。2.3.2GDB用法 gdb的基本命令: gdb提供的各種各樣的命令有著不同的功能。從簡(jiǎn)單到復(fù)雜,以下列出了一些常用的gdb調(diào)試命令: (1)filefilename:在gdb模式中無(wú)需退出即可通過(guò)file命令裝在你要調(diào)試的文件(gdb)filedavidReadingsymbolsfrom/home/david/Graduation_project/david...(nodebuggingsymbolsfound)...done.(2)kill:通過(guò)kill命令可以終止當(dāng)前正在調(diào)試的程序(gdb)killKilltheprogrambeingdebugged?(yorn)y還有一些常用的如:n(next)、s(step)、run和q(quit)將在下節(jié)例程中詳細(xì)說(shuō)明。2.3.1用gdb調(diào)試GCC程序 在終端輸入gdb回車后,會(huì)出現(xiàn)如下一長(zhǎng)串內(nèi)容: david@zdz:Graduation_project$gdbGNUgdb(Ubuntu/Linaro7.4-2012.04-0ubuntu2.1)7.4-2012.04Copyright(C)2012FreeSoftwareFoundation,Inc.LicenseGPLv3+:GNUGPLversion3orlater</licenses/gpl.html>Thisisfreesoftware:youarefreetochangeandredistributeit.ThereisNOWARRANTY,totheextentpermittedbylaw.Type"showcopying"and"showwarranty"fordetails.ThisGDBwasconfiguredas"x86_64-linux-gnu".Forbugreportinginstructions,pleasesee:</gdb-linaro/>.(gdb)Gdb的一些使用命令如果記不住的話可以查看官方手冊(cè),沒(méi)必要硬記,準(zhǔn)其自然,每次不會(huì)的時(shí)候翻翻手冊(cè),時(shí)間長(zhǎng)了自然就記住了下面只介紹一些常用的幾個(gè)命令:比方說(shuō),現(xiàn)在有一個(gè)通過(guò)gcc編譯好的可執(zhí)行文件david,在程序中我定義了兩個(gè)變量x,y賦初值為5,6終端執(zhí)行david@zdz:Graduation_project$./davidTheresultis:x+yis11x*yis30x/yis0那么通過(guò)gdb來(lái)看看發(fā)生了什么:david@zdz:Graduation_project$gdbdavid(gdb)我們現(xiàn)在告訴gdb使用窄于通常的顯示寬度:(gdb)setwidth70下面我要知到david這個(gè)程序怎樣工作的,通過(guò)閱讀源程序我大體知道工作流程,所以我可以設(shè)置斷點(diǎn): (gdb)breakcountBreakpoint1at0x400579接下來(lái)運(yùn)行程序:(gdb)runStartingprogram:/home/david/Graduation_project/davidTheresultis:Breakpoint1,0x0000000000400579incount()可以發(fā)現(xiàn)程序停在count()函數(shù)這個(gè)地方,Theresultis:這句話顯示count()函數(shù)之前都已運(yùn)行完畢。現(xiàn)在我可以通過(guò)n(next)讓程序執(zhí)行到下一行(gdb)nSinglesteppinguntilexitfromfunctioncount,whichhasnolinenumberinformation.x+yis11x*yis30x/yis00x0000000000400573inmain()還可用backtrace命令查看在棧中的什么位置,顯示每一個(gè)激活的子函數(shù)的棧結(jié)構(gòu):(gdb)backtrace#00x0000000000400573inmain() 通過(guò)輸入q(quit)退出gdb模式: (gdb)qAdebuggingsessionisactive. Inferior1[process3423]willbekilled.Quitanyway?(yorn)ydavid@zdz:Graduation_project$第三章設(shè)計(jì)的實(shí)現(xiàn)及主要技術(shù)3.1實(shí)現(xiàn)分析 本節(jié)主要對(duì)設(shè)計(jì)的功能和設(shè)計(jì)思路進(jìn)行簡(jiǎn)單的介紹3.1.1功能分析 客戶端的點(diǎn)點(diǎn)通信及文件的傳送。主要包括Server端和Client端: 1.Server端:主要負(fù)責(zé)處理用戶發(fā)送過(guò)來(lái)的消息,對(duì)用戶的系列動(dòng)作進(jìn)行管理(登陸、注冊(cè)、私聊、群聊)和對(duì)用戶的數(shù)據(jù)進(jìn)行管理(查看用戶的賬戶信息)。 2.Client端:主要可以和其他用戶私聊及群聊,還可以向其他用戶發(fā)送文件。3.1.2設(shè)計(jì)分析 服務(wù)器對(duì)Socket的初始化:網(wǎng)絡(luò)協(xié)議的指定、端口的指定,具體步驟將在Socket中進(jìn)行仔細(xì)介紹,等待用戶連接。Client通過(guò)socket()初始化一個(gè)socket并向server發(fā)送請(qǐng)求連接。當(dāng)服務(wù)器接收到用戶的連接請(qǐng)求時(shí),將為其開辟一個(gè)單獨(dú)的新的線程,這條線程就為此用戶服務(wù)。只有當(dāng)用戶退出時(shí)才將其釋放。而服務(wù)器的主線程仍在等待其他用戶的連接。系統(tǒng)設(shè)計(jì)大體框圖如圖3.1所示:3.1系統(tǒng)設(shè)計(jì)框圖3.1.3技術(shù)分析 基于以上簡(jiǎn)單的分析,Socket是實(shí)現(xiàn)C/S通信的接口,且使用TCP/IP協(xié)議。TCP協(xié)議是面向連接的、傳輸可靠的,且對(duì)網(wǎng)絡(luò)的適應(yīng)能力較強(qiáng),股本設(shè)計(jì)選用TCP,而不選用UDP。服務(wù)器要“同時(shí)”處理多個(gè)客戶的請(qǐng)求,就得實(shí)現(xiàn)多任務(wù)并發(fā)。對(duì)于單個(gè)處理器來(lái)講并發(fā)僅僅是概念上的,不是真正地同一時(shí)間處理多個(gè)任務(wù),而是多個(gè)任務(wù)輪流依次執(zhí)行,留給用戶的感覺(jué)就好像在同時(shí)處理多個(gè)任務(wù);而對(duì)于多喝CPU,則是真正意義上的并發(fā)執(zhí)行,效率總的來(lái)說(shuō)也有圖單核CPU。 線程并發(fā)的使用往往會(huì)牽涉到同步的問(wèn)題,mutex能解決此類問(wèn)題,當(dāng)然最主要的還是Scoket函數(shù)調(diào)用。 Ncurse終端字符界面大部分是由C++編寫,使用它只要將其安裝在本機(jī)上然后通過(guò)調(diào)用它的庫(kù)函數(shù)即可。3.2TCP/IP通信TCP/IP協(xié)議不同于OS模型,TCP/IP協(xié)議主要就以下幾個(gè)部分:應(yīng)用層、傳輸層、數(shù)據(jù)鏈路層和網(wǎng)絡(luò)接口層。各層示意圖如圖3.2所示:圖3.2TCP各層示意圖對(duì)于我們編程來(lái)說(shuō),沒(méi)有必要完全掌握每一層的細(xì)節(jié),只要知道:(1)每一層協(xié)議都是為下層向上層作轉(zhuǎn)換(2)沒(méi)有必要知道TCP的具體操作細(xì)節(jié),也不要知道IP及數(shù)據(jù)鏈路層的具體操作細(xì)節(jié)(3)從應(yīng)用程序的角度來(lái)看,僅僅把它們看成是SocketAPI就行了應(yīng)用到應(yīng)用之間的通信過(guò)程如圖3.3所示:圖3.3TCP/IP通信示意應(yīng)用層:應(yīng)用層的協(xié)議被大多數(shù)為用戶提供服務(wù)的應(yīng)用所使用,通過(guò)網(wǎng)絡(luò)向低層交換應(yīng)用數(shù)據(jù)。但這得包含一些基本的網(wǎng)絡(luò)支持服務(wù),如許多路由協(xié)議和主機(jī)配置協(xié)議。例如,應(yīng)用層常包含HTTP、FTP、SMTP、DHCP等協(xié)議。而且TCP/IP區(qū)分用戶協(xié)議和支持協(xié)議;支持協(xié)議提供系統(tǒng)服務(wù),而用戶協(xié)議提供用戶級(jí)應(yīng)用程序,比方說(shuō)FTP就是用戶協(xié)議,DNS是系統(tǒng)協(xié)議。傳輸控制層:TCP/IP協(xié)議族中有兩個(gè)傳輸層協(xié)議:UDP和TCP。UserDatagramProtocol(UDP)是通過(guò)數(shù)據(jù)報(bào)的方式傳輸,TransmissionControlProtocol(TCP)是通過(guò)流的形式傳輸。 數(shù)據(jù)鏈路層:從應(yīng)用角度來(lái)看,我們通??梢院雎詳?shù)據(jù)鏈接層,因?yàn)樗型ㄐ偶?xì)節(jié)在驅(qū)動(dòng)程序和硬件接口中處理。數(shù)據(jù)鏈路層(Data-LinkLayer)最重要的一個(gè)特性是最大傳輸單元Maximumtransmissionunit(MTU)。 網(wǎng)絡(luò)層:主要包括一下任務(wù):=1\*GB3①將數(shù)據(jù)分成足夠小的片段以便能夠通過(guò)數(shù)據(jù)鏈路層進(jìn)行傳輸(如果需要的話)=2\*GB3②通過(guò)Internet指定路徑發(fā)送數(shù)據(jù)=3\*GB3③為傳輸層提供服務(wù)=4\*GB3④IPv4和IPv6=5\*GB3⑤IP以數(shù)據(jù)包的形式傳送數(shù)據(jù)=6\*GB3⑥IP是無(wú)連接的和不可依賴的。為了建立連接,TCP常通過(guò)三次握手,三次握手示意圖如圖3.3.2:在客戶機(jī)試圖連接服務(wù)器時(shí),服務(wù)器必須首先必須打開一個(gè)端口并對(duì)其進(jìn)行綁定并監(jiān)聽;這通常叫做被動(dòng)連接,一旦被動(dòng)打開建立成功,客戶機(jī)就可以初始化一個(gè)主動(dòng)連接。為了建立一個(gè)連接,三次握手機(jī)制就起作用了:SYN:Client向Server發(fā)送主動(dòng)連接請(qǐng)求。Client設(shè)置序列號(hào)為隨機(jī)值xSYN_ACK:回應(yīng)請(qǐng)求,server發(fā)送SYN-ACK。序列號(hào)被設(shè)置成+1,eg:x+1;此時(shí)server產(chǎn)生另外一個(gè)隨機(jī)值y;ACK:最終,client向服務(wù)器發(fā)送回應(yīng),接收到的序列號(hào)已經(jīng)被設(shè)置成了x+1,server產(chǎn)生的序列號(hào)被設(shè)置成+1,eg:y+1。Client和Server都接收到了連接確認(rèn)包。(1)(2)兩步為單向(去)連接產(chǎn)生一個(gè)可識(shí)別的連接參數(shù);(2)(3)是為其他方向(回)產(chǎn)生一個(gè)可識(shí)別的連接參數(shù)。通過(guò)這些步驟,一個(gè)全雙工的通信就建立成功了。示意圖如圖3.4所示: 圖3.4三次握手示意圖3.3Socket(網(wǎng)絡(luò)套接字)SocketAPI,提供了許多例程和函數(shù)供程序員使用,以此開發(fā)TCP/IP網(wǎng)絡(luò)應(yīng)用程序。就像pipe,Socket用文件描述符來(lái)表示,但是區(qū)別于Pipe的是,Socket支持在兩個(gè)進(jìn)程之間甚至同一網(wǎng)絡(luò)中的不同機(jī)器上進(jìn)行通信。Socket基本上可以理解為和其他機(jī)器進(jìn)行通信;telnet,rlogin,ftp,talk等其他相似的網(wǎng)絡(luò)程序都是用sockets。但并不是所有機(jī)器都支持Socket。在GNU庫(kù)中,“sys/socket.h”存在于大多操作系統(tǒng)中,socket函數(shù)通常也都存在,但如果系統(tǒng)真的不支持socket,那么這些函數(shù)也就不會(huì)起作用了。當(dāng)創(chuàng)建socket時(shí),你必須指定使用那種通信類型及該使用那種協(xié)議去實(shí)現(xiàn)它。不同的通信類型定義了發(fā)送和接收數(shù)據(jù)的用戶級(jí)別,選擇一個(gè)通信類型你得考慮一下幾個(gè)方面:(1)傳輸?shù)臄?shù)據(jù)形式:bytes、packets(2)數(shù)據(jù)在傳輸過(guò)程中是否可以丟失:數(shù)據(jù)丟失程度不一樣對(duì)最終的結(jié)果影響是不一樣的;如果傳輸?shù)臄?shù)據(jù)不能丟失,那就得選用較可靠的協(xié)議。(3)通信是否是雙向的:就像打電話和發(fā)郵件的區(qū)別。在兩個(gè)程序,或許是不同的PC上進(jìn)行數(shù)據(jù)傳輸?shù)弥酪幌聨c(diǎn):(1)為了在兩個(gè)socket間進(jìn)行通信,這兩個(gè)socket必須制定相同的協(xié)議(2)每個(gè)協(xié)議都有自己的專屬定義,不能用其他協(xié)議的定義。(3)每個(gè)協(xié)議族都有一個(gè)默認(rèn)的協(xié)議,你可以通過(guò)指定0作為協(xié)議號(hào)。3.3.1編程步驟 Server端:socket()、bind()、listen()、accept()、send()、recv()、close(); Server端的編程步驟大體如上,建立連接后通過(guò)不斷地創(chuàng)建線程為Client提供服務(wù)。Clent端:socket()、connect()、send()、recv();Client端成功連接服務(wù)器后,創(chuàng)建一個(gè)新的接收線程從服務(wù)器不斷接收數(shù)據(jù)顯示在不同的界面。3.3.2地址及順序地址 1、地址結(jié)構(gòu)相關(guān)處理 (1)數(shù)據(jù)結(jié)構(gòu)介紹sockaddr結(jié)構(gòu)體有兩個(gè)成員:shortintsa_family、charsa_data[14];其原型如下: structsockaddr{unsignedshortsa_family;/*地址族*/charsa_data[14];//socket地址數(shù)據(jù)的真正長(zhǎng)度};sockaddr_in結(jié)構(gòu)體有三個(gè)成員:sin_family、sin_addr、sin_port;其原型如下:structsockaddr_in{sa_family_tsin_family;/*addressfamily*/in_port_tsin_port;/*portnumber*/structin_addrsin_addr;/*internetaddress*/};一般情況下,sockaddr_in結(jié)構(gòu)體使用起來(lái)更加方便。 (2)結(jié)構(gòu)字段 下表3.1列出了sa_family字段的常用值。 表3.1sa_family字段結(jié)構(gòu)定義頭文件#include<netinet/in.h>Sa_familyAF_INET:IPv4InternetprotocolsAF_INET6:IPv6InternetprotocolsAF_LOCAL:Localcommunication2、數(shù)據(jù)存儲(chǔ)優(yōu)先級(jí)(1)函數(shù)說(shuō)明 不同的計(jì)算機(jī)為一個(gè)word的存儲(chǔ)順序使用不同的約定。有些計(jì)算機(jī)將最重要的字節(jié)放到一個(gè)字的最開始(大端),而有些則是放到一個(gè)字的最后(小端)。網(wǎng)絡(luò)協(xié)議為傳輸?shù)臄?shù)據(jù)規(guī)定了字節(jié)順序,這就是大家所熟知的網(wǎng)絡(luò)字節(jié)序。因此有時(shí)候就需要對(duì)其進(jìn)行轉(zhuǎn)化。 用htons和ntohs為sin_port進(jìn)行轉(zhuǎn)化;用htonl和ntohl為sin_addr進(jìn)行IPv4地址的轉(zhuǎn)化。其中各個(gè)頭字母的含義如下: h:host;n:network;s:short;l:long (2)函數(shù)格式說(shuō)明 下表3.2列出了這四個(gè)函數(shù)的語(yǔ)法格式: 表3.2htons等函數(shù)定義所需頭文件#include<arpa/inet.h>#include<netinet/in.h>(somesysytem)函數(shù)原型uint32_thtonl(uint32_thostlong);uint16_thtons(uint16_thostshort);uint32_tntohl(uint32_tnetlong);uint16_tntohs(uint16_tnetshort);函數(shù)參數(shù)hostlong:主機(jī)字節(jié)序的32位數(shù)據(jù)hostshort:主機(jī)字節(jié)序的16位數(shù)據(jù)netlong:網(wǎng)絡(luò)字節(jié)序的32位數(shù)據(jù)netshort:網(wǎng)絡(luò)字節(jié)序的16位為數(shù)據(jù)函數(shù)返回值Success:返回要轉(zhuǎn)換的字節(jié)序Error:-13、地址格式轉(zhuǎn)化(1)函數(shù)說(shuō)明 用戶習(xí)慣性輸入的ip形式為:xxxx.xxxx.xxxx.xxxx或xxxx:xxxx:xxxx:xxxx,這兩種格式雖能被用戶識(shí)別,但是機(jī)器卻無(wú)法識(shí)別,故只有將其轉(zhuǎn)化成機(jī)器能識(shí)別的二進(jìn)制格式。經(jīng)常使用的有inet_aton、inet_addr、inet_pton、inet_ntop,其中后兩個(gè)兼容IPV6。inet_pton:將以.形式表示的十進(jìn)制轉(zhuǎn)換為為二進(jìn)制;inet_ntop:將二進(jìn)制轉(zhuǎn)換為以.形式表示的十進(jìn)制。(2)函數(shù)格式表3.3列出了inet_ntoa的語(yǔ)法要點(diǎn):表3.3inet_ntoa定義所需頭文件#inclide<arpa/inet.h>函數(shù)原型char*inet_ntoa(structin_addrin);函數(shù)參數(shù)in:網(wǎng)絡(luò)字節(jié)序的地址函數(shù)返回值Success:返回地址字符串表3.4列出了inet_addr的語(yǔ)法要點(diǎn):表3.4inet_addr語(yǔ)法要點(diǎn)所需頭文件#inclide<arpa/inet.h>函數(shù)原型in_addr_tinet_addr(constchar*cp);函數(shù)參數(shù)要轉(zhuǎn)換的字符串地址函數(shù)返回值Success:返回轉(zhuǎn)換后的二進(jìn)制地址3.3.3鏈接函數(shù)說(shuō)明 1、C/S連接示意圖C/S模式描述了應(yīng)用程序相互協(xié)作的關(guān)系。Server為一個(gè)或多個(gè)Client提供一個(gè)功能或服務(wù)。Server通常按其服務(wù)進(jìn)行分類歸檔。比方說(shuō)webserver提供網(wǎng)頁(yè)支持二fileserver則提供文件方面的服務(wù)。一個(gè)PC機(jī)扮演的角色是客戶機(jī)還是服務(wù)機(jī)還是兩者都是,通常取決于其應(yīng)用的需求。一個(gè)機(jī)器可以同時(shí)作為服務(wù)機(jī)和客戶機(jī);比方說(shuō),當(dāng)單機(jī)運(yùn)行webserver和fileserver同時(shí)服務(wù)于不同的請(qǐng)求;與此同時(shí),客戶機(jī)上的軟件能夠和同一臺(tái)計(jì)算機(jī)上的服務(wù)機(jī)軟件通訊。示意圖如圖3.5所示: 圖3.5Socket編程示意圖2、函數(shù)格式(1)socket()相關(guān)定義如下表3.5所示:表3.5socket函數(shù)定義原型intsocket(intdomains,inttype,intprotocol);函數(shù)說(shuō)明創(chuàng)建一個(gè)通信socket并返回一個(gè)描述符參數(shù)說(shuō)明domains指定通信地址族,即選擇什么協(xié)議用來(lái)通信。常用的幾個(gè)有AF_UNIX,AF_LOCALLocalcommunicationAF_INETIPv4InternetprotocolsAF_INET6IPv6Internetprotocolstype規(guī)定使用那種通信數(shù)據(jù)類型SOCK_STREAM提供有序、可靠、雙向,基于連接的字節(jié)流SOCK_DGRAM不可靠,無(wú)連接的數(shù)據(jù)包protocol指定domain地址族中某個(gè)特定的協(xié)議,通常情況下可以指定為0(2)bind()相關(guān)定義如下表3.6所示:表3.6bind函數(shù)定義原型intbind(intsock_fd,conststructsockaddr*addr,socklen_taddr_len)函數(shù)說(shuō)明給指定sock_fd的socket分配內(nèi)存地址空間參數(shù)說(shuō)明sock_fd創(chuàng)建socket時(shí)返回的文件描述符addr結(jié)構(gòu)體,用于存放ip和端口號(hào)addr_len結(jié)構(gòu)體addr的大小(3)listen()相關(guān)定義如下表3.7所示:表3.7listen函數(shù)定義原型intlisten(intsock_fd,intlen)函數(shù)說(shuō)明監(jiān)聽client連接的信號(hào),和accept()合同參數(shù)說(shuō)明sock_fd創(chuàng)建socket時(shí)返回的文件描述符len指定等待隊(duì)列的最大長(zhǎng)度(4)accept()相關(guān)定義如下表3.8所示:表3.8accept函數(shù)定義原型intaccept(intsock_fd,structsockaddr*addr,socklen_t*addr_len)函數(shù)說(shuō)明響應(yīng)連接等待隊(duì)列的隊(duì)頭請(qǐng)求,并創(chuàng)建新的socket,返回其文件描述符,新創(chuàng)建的socket并不會(huì)影響原先的socket參數(shù)說(shuō)明sock_fd創(chuàng)建socket時(shí)返回的文件描述符addr結(jié)構(gòu)體,用于存放ip和端口號(hào)addr_len結(jié)構(gòu)體addr的大小(5)connect()相關(guān)定義如下表3.9所示:表3.9connect函數(shù)定義原型intconnect(intsock_fd,conststructsockaddr*addr,socklen_taddr_len)函數(shù)說(shuō)明通過(guò)指定的sock_fd與socket連接進(jìn)而與其地址連接參數(shù)說(shuō)明sock_fd創(chuàng)建socket時(shí)返回的文件描述符addr結(jié)構(gòu)體,用于存放ip和端口號(hào)addr_len結(jié)構(gòu)體addr的大小(6)send()相關(guān)定義如下表3.10所示:表3.10send函數(shù)定義原型ssize_tsend(intsock_fd,constvoid*buf,size_tbuf_len,intflags)函數(shù)說(shuō)明往指定sock_fd的socket發(fā)送消息參數(shù)說(shuō)明buf發(fā)送數(shù)據(jù)存放的暫存區(qū)buf_len暫存區(qū)的大小(7)recv()相關(guān)定義如下表3.11所示:表3.11recv函數(shù)定義原型ssize_trecv(intsock_fd,void*buf,size_tbuf_len,intflags)函數(shù)說(shuō)明從指定sock_fd的socket中讀取數(shù)據(jù)參數(shù)說(shuō)明buf發(fā)送數(shù)據(jù)暫時(shí)存放的區(qū)域buf_len暫存區(qū)的大小(8)close()格式:close(fd)3.4進(jìn)程3.4.1進(jìn)程的概念(1)在說(shuō)明進(jìn)程前,先看一下什么是程序?程序就是一個(gè)文件,該文件包含了一系列信息,這些信息描述了如何在運(yùn)行時(shí)構(gòu)造一個(gè)進(jìn)程。(2)Linux平臺(tái)中可執(zhí)行程序類型=1\*GB3①可執(zhí)行目標(biāo)文件經(jīng)鏈接器鏈接后可直接執(zhí)行的文件。內(nèi)核通常支持幾種特定形式的可執(zhí)行文件。ELF格式是Linux系統(tǒng)中普遍使用的一種標(biāo)準(zhǔn)的可執(zhí)行文件格式。=2\*GB3②可執(zhí)行腳本Bash就是shell或者說(shuō)是命令行語(yǔ)言解釋器。GNU操作系統(tǒng)提供不同的shell,其中包含csh、ksh,但是bash是默認(rèn)的bsh。和其他GNU軟件一樣,bash是可移植的,其目前運(yùn)行在幾乎所有版本的Unix及其他的操作系統(tǒng)上,像MS-DOS、os/2和微軟平臺(tái)。當(dāng)Shell讀到輸入時(shí),展開一系列的操作。如果檢測(cè)到有注釋時(shí)會(huì)自動(dòng)忽略以‘#’開頭這一行。然后,shell將讀取到的內(nèi)容分成各個(gè)部分,再將這些解析成命令和其他結(jié)構(gòu),去掉一些特定的字或者字符,執(zhí)行特定的命令。下面是其執(zhí)行流程:1)從文件中讀取輸入2)將讀取到的內(nèi)容按引用準(zhǔn)則分成字和運(yùn)算符。這些標(biāo)號(hào)被通配符分隔3)將標(biāo)號(hào)解析成單一的或復(fù)合的命令4)執(zhí)行各種shell展開5)執(zhí)行一些必要的重定向并將這些操作符及操作數(shù)從參數(shù)列表中移除6)執(zhí)行命令7)選擇性的等待命令執(zhí)行完成并記錄退出狀態(tài)。(3)什么是進(jìn)程 進(jìn)程的專業(yè)定義,IEEEStd1003.1:“Anaddressspacewithoneormorethreadsexecutingwithinthataddressspace,andtherequiredsystemresourcesforthosethreads”。通俗的講,就是一個(gè)正在運(yùn)行的程序,每個(gè)程序都有自己的執(zhí)行狀態(tài)和地址空間,每個(gè)進(jìn)程相互獨(dú)立,除了兩個(gè)進(jìn)程發(fā)生通信,否則兩個(gè)進(jìn)程沒(méi)有多大關(guān)系。(4)不同進(jìn)程的區(qū)分方法(內(nèi)核)每個(gè)進(jìn)程都有一個(gè)屬于自己的id號(hào)叫做PID,就像我們每個(gè)人都有一個(gè)自己的身份證號(hào)一樣,PID標(biāo)識(shí)著這個(gè)進(jìn)程的存在。內(nèi)核通過(guò)這個(gè)PID來(lái)管理各個(gè)進(jìn)程的狀態(tài)和資源。一個(gè)內(nèi)核產(chǎn)生新的PID時(shí),內(nèi)核為這個(gè)PID分配系統(tǒng)資源,這樣一個(gè)進(jìn)程也就產(chǎn)生了。3.4.2進(jìn)程的內(nèi)存布局 進(jìn)程內(nèi)存分布圖如圖3.6所示:從低地址到高地址依次分布圖3.6進(jìn)程內(nèi)存分布3.4.3進(jìn)程生命周期 =1\*GB3①創(chuàng)建:進(jìn)程的創(chuàng)建是由其父進(jìn)程通過(guò)folk來(lái)創(chuàng)建的。下圖描述了進(jìn)程的創(chuàng)建過(guò)程:=2\*GB3②運(yùn)行:同一系統(tǒng)中可以有多個(gè)進(jìn)程同時(shí)運(yùn)行,并且能夠互相通信。試想一下,一個(gè)系統(tǒng)上同一時(shí)刻只能運(yùn)行一個(gè)進(jìn)程,要開其他進(jìn)程必須得先將本進(jìn)程關(guān)閉掉,那是得有多么麻煩。 =3\*GB3③終止結(jié)束一個(gè)進(jìn)程的運(yùn)行。3.5多線程3.5.1線程的概念 線程是系統(tǒng)最小的調(diào)度單元,是操作系統(tǒng)的重要組成部分。操作系統(tǒng)中,線程和進(jìn)程的實(shí)現(xiàn)是不同的,單線程通常是進(jìn)程的一部分。多個(gè)線程可以在同一個(gè)進(jìn)程中執(zhí)行,和進(jìn)程共享內(nèi)存資源,這是不同進(jìn)程之間所不能做到的。與進(jìn)程相比,線程沒(méi)有自己獨(dú)立的地址空間,創(chuàng)建出來(lái)的新線程將和創(chuàng)建它的進(jìn)程(或線程)共享一個(gè)虛擬地址空間,它們被置于同一個(gè)線程組中。每個(gè)線程都有自己獨(dú)立的棧空間。不管是服務(wù)器還是客戶機(jī)都包含信息的一收一發(fā)兩個(gè)過(guò)程。同時(shí)使用主線程去收發(fā)信息是不可取的,因?yàn)槭招畔⑹潜粍?dòng)的,當(dāng)沒(méi)有信息可收時(shí)主線程就會(huì)阻塞,從而影響信息的發(fā)送。而創(chuàng)建兩個(gè)進(jìn)程的方法在這里也是是不可取的,因?yàn)椴煌倪M(jìn)程對(duì)應(yīng)不同的端口號(hào),但是信息的發(fā)送和接收必須使用同一端口。因此必須創(chuàng)建多個(gè)線程來(lái)完成不同的收發(fā)任務(wù)。3.5.2進(jìn)程和線程的關(guān)系及優(yōu)缺點(diǎn)線程在進(jìn)程中的分布如圖3.7所示:圖3.7進(jìn)程中的線程 使用線程的優(yōu)點(diǎn): =1\*GB3①較快的執(zhí)行(Fasterexecution):在多核CPU上執(zhí)行明顯快于單核CPU,且上下文狀態(tài)的切換比進(jìn)程快;=2\*GB3②響應(yīng)迅速(Responsiveness):當(dāng)主線程阻塞時(shí),其他線程仍可和用戶進(jìn)行交互; =3\*GB3③對(duì)資源的需求小(Lowerresourceconsumption):用較少的系統(tǒng)資源服務(wù)于更多的用戶; =4\*GB3④更好的系統(tǒng)利用(Bettersystemutilization):能更好的利用內(nèi)存的資源;=5\*GB3⑤簡(jiǎn)單的分享和通信(Simplifiedsharingandcommunication);=6\*GB3⑥并行化(Parallelization):多個(gè)線程同時(shí)對(duì)一個(gè)任務(wù)進(jìn)行操作。但是線程也有一些缺點(diǎn):=1\*GB3①同步(\o"Synchronization(computerscience)"Synchronization):由于共用相同的地址空間,那么就要很好的解決競(jìng)爭(zhēng)和其他的非正常行為。如果處理不好,會(huì)造成死鎖的情況,那么進(jìn)程就會(huì)變?yōu)榻┧肋M(jìn)程;=2\*GB3②在進(jìn)程中崩潰(Crashinprocess):線程的非法操作從而造成整個(gè)進(jìn)程的退出。3.5.3數(shù)據(jù)類型及其用法1、函數(shù)簡(jiǎn)要說(shuō)明如下表3.12所示:表3.12線程函數(shù)定義函數(shù)功能typedefunsignedlongintpthread_t/usr/include/bits/pthreadtypes.hpthread_create()創(chuàng)建一個(gè)線程pthread_exit()終止當(dāng)前線程pthread_join()阻塞當(dāng)前線程,直到另一線程退出2、線程的創(chuàng)建與結(jié)束(1)新線程的創(chuàng)建可通過(guò)pthread_create(),定義及說(shuō)明如下表3.13所示:表3.13pthread_create函數(shù)定義原型intpthread_create(pthread_t*thread,constpthread_attr_t*attr,void*(*start_routine)(void*),void*args);參數(shù)說(shuō)明thread指向一個(gè)pthread_t型變量,用于返回線程IDattr指定各種不同屬性,若設(shè)為NULL,表示默認(rèn)屬性start_routine新線程的工作函數(shù)args傳遞給執(zhí)行函數(shù)的參數(shù)返回值0表示執(zhí)行成功,出錯(cuò)返回錯(cuò)誤編號(hào)(EAGAIN、EINVAL)(2)pthread_join(),等待一個(gè)線程執(zhí)行結(jié)束(與waitpid()類似),相關(guān)定義如下表3.14所示:表3.13pthread_join函數(shù)定義原型intpthread_join(pthread_tthread,void**value_ptr)參數(shù)說(shuō)明thread指定要等待哪個(gè)線程value_ptr是指向(void*)型數(shù)據(jù)的指針,用于獲得線程的退出狀態(tài)(thevaluethatwasspecifiedwhenthethreadperformedareturnorcalledpthread_exit()),如果不需要退出狀態(tài)則可將其設(shè)為NULL返回值成功返回0,錯(cuò)誤返回一個(gè)非負(fù)數(shù)(3)pthread_exit()voidpthread_exit(void*value_ptr);該函數(shù)終止當(dāng)前線程(callingthread),并且指定一個(gè)返回值,返回值可以在其他線程中通過(guò)調(diào)用pthread_join()獲得。綜上所述,線程在一下情況下退出:=1\*GB3①程序調(diào)用pthread_exit()=2\*GB3②調(diào)用pthread_cancle()=3\*GB3③從回調(diào)函數(shù)start_routine中返回=4\*GB3④調(diào)用exit(),或者主線程退出(終止進(jìn)程中所有的線程)3.6線程同步3.6.1概念 線程同步,顧名思義就是對(duì)某一塊內(nèi)存的操作的先后順序。當(dāng)這塊內(nèi)存中的數(shù)據(jù)是只讀的,那么其他線程都可以對(duì)其進(jìn)行讀取,那就沒(méi)什么問(wèn)題;或者說(shuō)這塊內(nèi)存中的數(shù)據(jù)不會(huì)被其他線程讀取或修改,那么也不存在同步的問(wèn)題。只有當(dāng)多個(gè)線程同時(shí)對(duì)某一塊內(nèi)存中的數(shù)據(jù)進(jìn)行修改時(shí),多個(gè)線程都要對(duì)其進(jìn)行修改,那么到底是哪一個(gè)線程先修改呢,此時(shí)就涉及到同步的問(wèn)題。3.6.2線程同步的幾種方法:信號(hào)量、自旋鎖、互斥量 信號(hào)量:操作系統(tǒng)之中,信號(hào)量通常是一個(gè)多個(gè)進(jìn)程或線程用于控制訪問(wèn)權(quán)限的變量或抽象數(shù)據(jù)類型。信號(hào)量可被增加或減少,但將保證對(duì)其關(guān)鍵的是原子操作,即有多個(gè)線程試圖改變一個(gè)信號(hào)量的值時(shí),系統(tǒng)將保證所有操作依次進(jìn)行。自旋鎖:線程為了獲得自旋鎖,通過(guò)不斷循環(huán)檢查該鎖是否可獲得。這個(gè)鎖是出于激活狀態(tài)的,但是對(duì)當(dāng)前任務(wù)并不可用,這就有點(diǎn)類似于忙時(shí)等待的情況。一旦獲得,當(dāng)前線程將會(huì)執(zhí)行,同時(shí)該鎖也會(huì)被處理直到被釋放,在一些實(shí)現(xiàn)中可能會(huì)自動(dòng)釋放。 互斥量(mutex)從概念上講有點(diǎn)類似于一個(gè)初始值為1二進(jìn)制信號(hào)量。互斥量被獲取之后就不能再被獲取,因此對(duì)互斥體的獲取和釋放操作常常稱為加鎖和解鎖操作。互斥量只能由獲取它的線程進(jìn)行釋放,如果違反這一原則,則結(jié)果是未定義的。 互斥量就是當(dāng)前線程對(duì)其正在訪問(wèn)的共享資源上鎖,等其用完了,再對(duì)其進(jìn)行解鎖,讓其他等待的線程使用。當(dāng)一個(gè)共享資源被mutex上鎖后,其他任何線程都無(wú)法對(duì)這塊共享資源進(jìn)行修改。3.6.3互斥量的使用互斥量用一個(gè)pthread_mutex_t型的變量表示。其定義如下表3.15所示:表3.15pthread_mutex_init函數(shù)定義原型intpthread_mutex_init(pthread_mutex_t*mutex,constpthread_mutexattr_t*attr);函數(shù)說(shuō)明對(duì)mutex進(jìn)行初始化參數(shù)說(shuō)明mutex指向要初始化的互斥量attr參數(shù)可以為NULL,表示使用默認(rèn)屬性互斥量不用以后,應(yīng)該使用下面的函數(shù)進(jìn)行銷毀:intpthread_mutex_destroy(pthread_mutex_t*mutex);互斥量的主要操作函數(shù)如下表3.16所示:表3.16互斥量主要函數(shù)說(shuō)明函數(shù)原型簡(jiǎn)要說(shuō)明intpthread_mutex_lock(pthread_mutex_t*mutex)上鎖intpthread_mutex_trylock(pthread_mutex_t*mutex)上鎖intpthread_mutex_unlock(pthread_mutex_t*mutex)解鎖 各函數(shù)詳細(xì)說(shuō)明:pthread_mutex_lock():將其指向的資源加鎖。如果這時(shí)互已經(jīng)被鎖,則調(diào)用這個(gè)函數(shù)的線程將被阻塞,直到其成為未鎖狀態(tài)。函數(shù)返回時(shí),表示這個(gè)互斥量已經(jīng)變?yōu)橐焰i狀態(tài),同時(shí),函數(shù)的調(diào)用者成為這個(gè)互斥量的擁有者。pthread_mutex_trylock():用于對(duì)參數(shù)指向的互斥量進(jìn)行加鎖。try表明試試的意思,即就是試探一下是否可獲得鎖,如果不可獲得那就一錯(cuò)誤狀態(tài)返回,該線程不阻塞。pthread_mutex_unlock():將參數(shù)指向的互斥量解鎖。解鎖的對(duì)象必須是當(dāng)前線程所擁有的。如果這時(shí)互斥量是未鎖狀態(tài)或不是當(dāng)前線程所擁有的,則結(jié)果未定義。3.7ncurrses字符界面3.7.1ncurses簡(jiǎn)介 一個(gè)提供了供編程人員開發(fā)字符終端界面的接口的程序庫(kù)。是一個(gè)開發(fā)運(yùn)行在終端模擬器上的類似于“GUI”的應(yīng)用軟件。為了減少使用遠(yuǎn)程終端的延遲,其對(duì)屏幕的改變進(jìn)行了優(yōu)化。 發(fā)展史:從curses到pcurses再到ncurses Curses:第一版是在加利福尼亞伯克利分校開發(fā)的。一開始使用的是termcap庫(kù),這個(gè)庫(kù)通常用在其他程序中,如vi編輯器; Pcurses:PavelCurtis克隆了BellLabscurses,在1986年期間由很多人維護(hù)著; Ncurses:1991年后期pcurses庫(kù)由ZeydBen-Halim接手開發(fā),到1993年11月ncurses1.8.1版本發(fā)布了。由EricSRaymod加入了JuergenPfeifr編寫的菜單庫(kù)。自從1996年,ncurses被ThomasE.Dickey維護(hù)著。3.7.2ncurses常用函數(shù)介紹1. 初始化ncurses:WINDOW*initscr(void);函數(shù)說(shuō)明:initscr()務(wù)必在其他任何影響窗口結(jié)構(gòu)的函數(shù)之前調(diào)用。它捕捉terminal的特性并初始化所有curses相關(guān)的數(shù)據(jù)結(jié)構(gòu)。即將屏幕刷新一下;返回值:返回一個(gè)WINDOW類型的結(jié)構(gòu)體指針;Success:返回一個(gè)指向stdscr(代表默認(rèn)窗口)的指針;Error:輸出標(biāo)準(zhǔn)錯(cuò)誤信息然后退出。2. 輸出格式串函數(shù):intprintw(constchar*fmt,...);//和printf函數(shù)用法一樣。3. 刷新屏幕內(nèi)容:intrefresh(void);函數(shù)描述:當(dāng)一個(gè)窗口中的結(jié)構(gòu)被改變時(shí),必須調(diào)用refresh刷新一下新的內(nèi)容才能顯示出來(lái)。4. 輸入一個(gè)字符:intgetch(void);函數(shù)描述:獲取用戶輸入的一個(gè)字符;函數(shù)返回值:成功返回用戶按下的鍵值,失敗返回error。5. 離開ncurses:intendwin(void);函數(shù)描述:退出ncurses時(shí)將會(huì)被調(diào)用,退回到普通模式。6. 創(chuàng)建窗口類函數(shù):WINDOW*newwin(intlines,intcols,intbegin_y,intbegin_x);函數(shù)說(shuō)明:創(chuàng)建并返回一個(gè)指向特定行數(shù)和列數(shù)的指針,開始的位置由begin_y和begin_x兩個(gè)參數(shù)決定。7. 屬性設(shè)置:intattr_on(attr_tattrs,void*opt);函數(shù)說(shuō)明:attr_on/attr_off是打開或者關(guān)閉特定的屬性而不影響其他的屬性。倘若用attrset的話,前面所有的設(shè)置將會(huì)被覆蓋。8. 畫線類,方框類:intmvwvline(WINDOW*win,inty,intx,chtypech,intn);9. 輸出控制函數(shù):intscrollok(WINDOW*win,boolbf);函數(shù)說(shuō)明:允許指定的窗口滾動(dòng),就上當(dāng)顯示到窗口最下面一行時(shí),可以下上滾動(dòng)顯示。10. 更新窗口類函數(shù):inttouchwin(WINDOW*win);函數(shù)說(shuō)明:使整個(gè)窗口看起來(lái)被重繪了,在接下來(lái)調(diào)用refresh()或者wrefresh()時(shí)重繪整個(gè)窗口。第四章設(shè)計(jì)的編程實(shí)現(xiàn)4.1聊天室Socket編程連接 1、監(jiān)聽連接過(guò)程 socket函數(shù)創(chuàng)建Socket、bind函數(shù)對(duì)創(chuàng)建的Socket進(jìn)行綁定、listen函數(shù)對(duì)其進(jìn)行監(jiān)聽。Socket()初始化socket,創(chuàng)建新的sockfdsockfd=socket(AF_INET,SOCK_STREAM,0);此過(guò)程涉及到ip地址的處理 saddr.sin_addr.s_addr=htonl(INADDR_ANY);bind()綁定端口號(hào)和ip地址saddr.sin_family=AF_INET;saddr.sin_port=htons(PORT);bind(sockfd,(structsockaddr*)&addr,len);listen()監(jiān)聽listen(sockfd,BACKLOG); 2、發(fā)送請(qǐng)求 (1)獲取主機(jī)信息 (2)對(duì)socket端口初始化 socket(AF_INET,SOCK_STREAM,0) addr.sin_family=AF_INET; addr.sin_port=htons(8010);//指定一個(gè)端口號(hào),大于3000就行,因?yàn)?000一下的端口供系統(tǒng)使用inet_aton("",&addr.sin_addr); (3)調(diào)用connect()請(qǐng)求Server連接,等待服務(wù)器響應(yīng) connect(fd,(structsockaddr*)&addr,socket_len) 3、server接受請(qǐng)求,進(jìn)行數(shù)據(jù)通信 (1)server通過(guò)accept()接收Client的請(qǐng)求; (2)匹配用戶操作 1).登陸,創(chuàng)建登陸線程 2).注冊(cè),創(chuàng)建注冊(cè)線程 (3)登陸成功,接受返回信息,一系列操作后退出連接 (4)將客戶端口socket關(guān)閉 上述簡(jiǎn)要的步驟是server端應(yīng)用程序監(jiān)聽請(qǐng)求,在此過(guò)程中,服務(wù)器線程一直處于休眠狀態(tài),直到有client向其發(fā)送連接請(qǐng)求。當(dāng)server收到連接請(qǐng)求時(shí),server主線程調(diào)用accept()接收請(qǐng)求,同時(shí)為client創(chuàng)建一個(gè)新的線程為其服務(wù)。然后server主線程繼續(xù)等待新用戶的連接。這樣的系列步驟也就實(shí)現(xiàn)了socket通訊,如圖4.1所示圖4.1單個(gè)client和server之間Socket連接4.2聊天室程序設(shè)計(jì)及界面設(shè)計(jì)4.2.1服務(wù)器 服務(wù)器端的程序?qū)懞煤?,需要進(jìn)行聯(lián)編,可以通過(guò)寫makefile,也可以寫一個(gè)shell腳本,將要執(zhí)行的文件名按終端命令的模式寫進(jìn)腳本。 本設(shè)計(jì)是通過(guò)寫shell腳本,只要在終端執(zhí)行腳本即可,命令如下: ./server.sh 編譯成功后會(huì)生成一個(gè)可執(zhí)行文件server,如果出錯(cuò)按照錯(cuò)誤提示排錯(cuò)即可。 在終端執(zhí)行./server,服務(wù)器啟動(dòng),一直等待用戶連接并為其服務(wù),直到退出為止,啟動(dòng)界面如圖4.2所示:圖4.2服務(wù)端啟動(dòng)界面4.2.2客戶端 1、進(jìn)入客戶端主界面 客戶端的編譯過(guò)程和server端一樣,同樣是通過(guò)shell腳本,在終端執(zhí)行./client.sh編譯成功后會(huì)生成一個(gè)可執(zhí)行文件logo,終端執(zhí)行:[zdz@david]$./logo客戶端啟動(dòng),啟動(dòng)界面如圖4.3所示:圖4.3客戶端啟動(dòng)界面剛開始的界面上有登陸、注冊(cè)、幫助、退出四個(gè)選項(xiàng)=1\*GB3①Login:用戶輸入自己的賬號(hào)和密碼,如圖4.4所示:圖4.4登陸窗口界面=2\*GB3②Register:填寫名字、密碼、驗(yàn)證信息及驗(yàn)證答案,如圖4.5所示:圖4.5注冊(cè)界面=3\*GB3③Help:顯示幫助信心,如圖4.6所示:圖4.6幫助界面=4\*GB3④Exit:退出客戶端。登陸窗口的創(chuàng)建過(guò)程:=1\*GB3①初始化ncurses,即刷新終端,初始化終端背景=2\*GB3②通過(guò)調(diào)用newwin(LINES/3,COLS/2,LINES/4,COLS/4)函數(shù)創(chuàng)建登陸注冊(cè)窗口:LINES為整個(gè)終端的行數(shù),COLS為整個(gè)終端的
溫馨提示
- 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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 售后服務(wù)協(xié)議合同常見(jiàn)問(wèn)題
- 空調(diào)內(nèi)部結(jié)構(gòu)優(yōu)化質(zhì)保服務(wù)
- 采購(gòu)合同樣式集錦
- 燈具安裝合同樣本
- 計(jì)劃成長(zhǎng)擔(dān)保
- 心理測(cè)評(píng)與咨詢協(xié)議
- 退款協(xié)議書合同范本
- 重建幸福家庭的諾言
- 別墅石材招標(biāo)文件
- 工作責(zé)任保證書樣本
- 咸水沽污水廠生物池清淤施工組織方案
- 二甘醇二苯甲酸酯(DEDB)
- 數(shù)字化變電站的IEC61850建模
- 管道閉水試驗(yàn)記錄表自動(dòng)計(jì)算軟件
- 學(xué)校綜合督導(dǎo)匯報(bào)ppt課件
- 人流咨詢?cè)捫g(shù)
- 鐵路建設(shè)征地拆遷補(bǔ)償標(biāo)準(zhǔn)(附表)
- 農(nóng)村祠堂上梁說(shuō)辭
- GB31644-2018食品安全國(guó)家標(biāo)準(zhǔn)復(fù)合調(diào)味料
- 建筑施工現(xiàn)場(chǎng)安全檢查的程序及要點(diǎn)
- 市政工程溝槽開挖與回填自動(dòng)計(jì)算表
評(píng)論
0/150
提交評(píng)論