




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第六章-Linux網(wǎng)絡(luò)程序設(shè)計(jì)基本要求1、了解TCP/IP基礎(chǔ)知識(shí),什么是socket,socket編程,遠(yuǎn)程過程調(diào)用。2、掌握Linux平臺(tái)數(shù)據(jù)結(jié)構(gòu)的傳送方法。TCP/IP協(xié)議概述OSI參考模型與TCP/IP參考模型應(yīng)用層表示層會(huì)話層傳輸層網(wǎng)絡(luò)層數(shù)據(jù)鏈路層物理層應(yīng)用層傳輸層網(wǎng)絡(luò)層網(wǎng)絡(luò)接口層OSI參考模型TCP/IP參考模型OSI參考模型與TCP/IP參考模型對(duì)應(yīng)關(guān)系TCP/IP協(xié)議族TCP/IP實(shí)際上一個(gè)一起工作的通信家族,為網(wǎng)際數(shù)據(jù)通信提供通路。為討論方便可將TCP/IP協(xié)議組大體上分為三部分:1.Internet協(xié)議(IP)2.傳輸控制協(xié)議(TCP)和用戶數(shù)據(jù)報(bào)文協(xié)議(UDP)3.處于TCP和UDP之上的一組協(xié)議專門開發(fā)的應(yīng)用程序。它們包括:TELNET,文件傳送協(xié)議(FTP),域名服務(wù)(DNS)和簡(jiǎn)單的郵件傳送程序(SMTP)等許多協(xié)議。網(wǎng)絡(luò)層第一部分也稱為網(wǎng)絡(luò)層。包括Internet協(xié)議(IP)、網(wǎng)際控制報(bào)文協(xié)議(ICMP)和地址識(shí)別協(xié)議(ARP).Internet協(xié)議(IP)。該協(xié)議被設(shè)計(jì)成互聯(lián)分組交換通信網(wǎng),以形成一個(gè)網(wǎng)際通信環(huán)境。它負(fù)責(zé)在源主機(jī)和目的地主機(jī)之間傳輸來自其較高層軟件的稱為數(shù)據(jù)報(bào)文的數(shù)據(jù)塊,它在源和目的地之間提供非連接型傳遞服務(wù)。
網(wǎng)際控制報(bào)文協(xié)議(ICMP)。它實(shí)際上不是IP層部分,但直接同IP層一起工作,報(bào)告網(wǎng)絡(luò)上的某些出錯(cuò)情況。允許網(wǎng)際路由器傳輸差錯(cuò)信息或測(cè)試報(bào)文。地址識(shí)別協(xié)議(ARP)。ARP實(shí)際上不是網(wǎng)絡(luò)層部分,它處于IP和數(shù)據(jù)鏈路層之間,它是在32位IP地址和48位局域網(wǎng)物理地址之間執(zhí)行翻譯的協(xié)議。傳輸層協(xié)議第二部分是傳輸層協(xié)議。包括傳輸控制協(xié)議和用戶數(shù)據(jù)報(bào)文協(xié)議。
傳輸控制協(xié)議(TCP)。由于IP提供非連接型傳遞服務(wù),因此TCP應(yīng)為應(yīng)用程序存取網(wǎng)絡(luò)創(chuàng)造了條件,使用可靠的面向連接的傳輸層服務(wù)。該協(xié)議為建立網(wǎng)際上用戶進(jìn)程之間的對(duì)話負(fù)責(zé)。此外,還確保兩個(gè)以上進(jìn)程之間的可靠通信。它所提供的功能如下。1.監(jiān)聽輸入對(duì)話建立請(qǐng)求。2.請(qǐng)求另一網(wǎng)絡(luò)站點(diǎn)對(duì)話。3.可靠的發(fā)送和接收數(shù)據(jù)。4.適度的關(guān)閉對(duì)話。應(yīng)用程序部分用戶數(shù)據(jù)報(bào)文協(xié)議(UDP)。UDP提供不可靠的非連接型傳輸層服務(wù),它允許在源和目的地站點(diǎn)之間傳送數(shù)據(jù),而不必在傳送數(shù)據(jù)之前建立對(duì)話。此外,該協(xié)議還不使用TCP使用的端對(duì)端差錯(cuò)校驗(yàn)。當(dāng)使用UDP時(shí),傳輸層功能全都發(fā)揮,而開銷卻比較低。它主要用于那些不要求TCP協(xié)議的非連接型的應(yīng)用程序。例如,名字服務(wù)、網(wǎng)絡(luò)管理、視頻點(diǎn)播和網(wǎng)絡(luò)會(huì)議等。最后是應(yīng)用程序部分。這部分包括Telnet,文件傳送協(xié)議(FTP和TFTP),簡(jiǎn)單的文件傳送協(xié)議(SMTP)和域名服務(wù)(DNS)等協(xié)議。TCP/IP使用了主干網(wǎng)絡(luò),能連接各種主機(jī)和LAN的多級(jí)分層結(jié)構(gòu),局部用戶能方便的聯(lián)網(wǎng),不致影響到整個(gè)網(wǎng)絡(luò)系統(tǒng)。此外這種結(jié)構(gòu)還有利于局部用戶控制操作和管理。TCP/IP具有兩個(gè)主要功能。第一是IP在網(wǎng)絡(luò)之間(有時(shí)在個(gè)別網(wǎng)絡(luò)內(nèi)部)提供路由選擇。第二是TCP將TP傳遞的數(shù)據(jù)傳送的接收主機(jī)那的適當(dāng)?shù)奶幚聿考?。Internet協(xié)議(IP)IP主要有以下四個(gè)主要功能:(1)數(shù)據(jù)傳送(2)尋址(3)路由選擇(4)數(shù)據(jù)報(bào)文的分段IP功能IP的主要目的是為數(shù)據(jù)輸入/輸出網(wǎng)絡(luò)提供基本算法,為高層協(xié)議提供無連接的傳送服務(wù)。這意味著在IP將數(shù)據(jù)遞交給接收站點(diǎn)以前不在傳輸站點(diǎn)和接收站點(diǎn)之間建立對(duì)話(虛擬鏈路)。它只是封裝和傳遞數(shù)據(jù),但不向發(fā)送者或接收者報(bào)告包的狀態(tài),不處理所遇到的故障。IP協(xié)議不注意包內(nèi)的數(shù)據(jù)類型,它所知道的一切是必須將某些稱為IP幀頭的控制協(xié)議加到高層協(xié)議(TCP或者UDP)所接受的數(shù)據(jù)上。IP地址IP地址為32位地址,一般以4個(gè)字節(jié)表示。每個(gè)字節(jié)的數(shù)字又用十進(jìn)制表示,即每個(gè)字節(jié)的數(shù)的范圍是0~255,且每個(gè)數(shù)字之間用點(diǎn)隔開,例如:12,這種記錄方法稱為“點(diǎn)-分”十進(jìn)制記號(hào)法。IP地址的結(jié)構(gòu)如下所示:網(wǎng)絡(luò)類型網(wǎng)絡(luò)ID主機(jī)IDIP地址的分類Internet地址可分成5類:A、B、C三類由InterNIC(Internet網(wǎng)絡(luò)信息中心)在全球范圍內(nèi)統(tǒng)一分配,D、E類為特殊地址。
01 78 310網(wǎng)絡(luò)地址ID主機(jī)地址IDA類IP地址10網(wǎng)絡(luò)地址ID主機(jī)地址ID0121516 31B類IP地址110網(wǎng)絡(luò)地址ID主機(jī)地址ID01232324 31C類IP地址1110廣播地址ID01234 31D類IP地址11110保留用于將來和試驗(yàn)使用012345 31E類IP地址IP地址說明A類網(wǎng)絡(luò)地址有128個(gè)(支持127)個(gè)網(wǎng)絡(luò),占有最左邊的一個(gè)字節(jié)(8位)。高位(0)表示識(shí)別這種地址的類型。B類地址使用左邊兩個(gè)8位用來網(wǎng)絡(luò)尋址。兩個(gè)高位(10)用于識(shí)別這種地址的類型,其余的14位用作網(wǎng)絡(luò)地址,右邊的兩個(gè)字節(jié)(16位)用作網(wǎng)絡(luò)節(jié)點(diǎn)。C類地址是最常見的Internet地址。三個(gè)高位(110)用于地址類型識(shí)別,左邊三個(gè)字節(jié)的其余21位用于尋址。C類地址支持1046個(gè)網(wǎng)絡(luò),每個(gè)網(wǎng)絡(luò)可多達(dá)256端點(diǎn)。D類地址是相當(dāng)新的。它的識(shí)別頭是1110,用于組播,例如用于路由器修改。E類地址為時(shí)延保留,其識(shí)別頭是11110。傳輸控制協(xié)議(TCP)TCP(傳輸控制協(xié)議TransmissionControlProtocol)是重要的傳輸層協(xié)議,傳輸層軟件TCP的目的是允許數(shù)據(jù)同網(wǎng)絡(luò)上的另外站點(diǎn)進(jìn)行可靠的交換。它能提供端口編號(hào)的譯碼,以識(shí)別主機(jī)的應(yīng)用程序,而且完成數(shù)據(jù)的可靠傳輸。TCP協(xié)議具有嚴(yán)格的內(nèi)裝差錯(cuò)檢驗(yàn)算法確保數(shù)據(jù)的完整性。TCP是面向字節(jié)的順序協(xié)議,這意味著包內(nèi)的每個(gè)字節(jié)被分配一個(gè)順序編號(hào),并分配給每包一個(gè)順序編號(hào)。TCP頭信息用戶數(shù)據(jù)報(bào)文協(xié)議UDP(用戶數(shù)據(jù)報(bào)協(xié)議UserDatagramProtocol)也是TCP/IP的傳輸層協(xié)議,它是無連接的,不可靠的傳輸服務(wù)。當(dāng)接收數(shù)據(jù)時(shí)它不向發(fā)送方提供確認(rèn)信息,它不提供輸入包的順序,如果出現(xiàn)丟失包或重份包的情況,也不會(huì)向發(fā)送方發(fā)出差錯(cuò)報(bào)文。UDP的主要作用是分配和管理端口編號(hào),以正確無誤的識(shí)別運(yùn)行在網(wǎng)絡(luò)站點(diǎn)上的個(gè)別應(yīng)用程序。由于它執(zhí)行功能時(shí)具有較低的開銷,因而執(zhí)行速度比TCP快。它多半用于不需要可靠傳輸?shù)膽?yīng)用程序,例如網(wǎng)絡(luò)視頻點(diǎn)播和視頻會(huì)議等。UDP頭信息TCP/IP協(xié)議分組服務(wù)控制數(shù)據(jù)的協(xié)議TCP以連接為基礎(chǔ),即兩臺(tái)電腦必須先建立一個(gè)連接,然后才能傳輸數(shù)據(jù)。事實(shí)上,發(fā)送和接受的電腦必須一直互相通訊和聯(lián)系。UDP是一個(gè)無連接服務(wù),數(shù)據(jù)可以直接發(fā)送而不必在兩臺(tái)電腦之間建立一個(gè)網(wǎng)絡(luò)連接。它和有連接的TCP相比,占用帶寬少,但是無法確認(rèn)數(shù)據(jù)是否真正到達(dá)了客戶端,而客戶端收到的數(shù)據(jù)也不知道是否還是原來的發(fā)送順序。數(shù)據(jù)路由協(xié)議路由協(xié)議分析數(shù)據(jù)包的地址并且決定傳輸數(shù)據(jù)到目的電腦最佳路線。他們也可以把大的數(shù)據(jù)分成幾部分,并且在目的地再把他們組合起來。IP處理實(shí)際上傳輸數(shù)據(jù)。ICMP(網(wǎng)絡(luò)控制信息協(xié)議InternetControlMessageProtocol)處理IP的狀態(tài)信息,比如能影響路由決策的數(shù)據(jù)錯(cuò)誤或改變。RIP(路由信息協(xié)議RoutingInformationProtocol)它是幾個(gè)決定信息傳輸?shù)淖罴崖酚陕肪€協(xié)議中的一個(gè)。OSPF(OpenShortestPathFirst)一個(gè)用來決定路由的協(xié)議。ARP(地址解析協(xié)議AddressResolutionProtocol)確定網(wǎng)絡(luò)上一臺(tái)電腦的數(shù)字地址。DNS(域名系統(tǒng)DomainNameSystem)從機(jī)器的名字確定一個(gè)機(jī)器的數(shù)字地址。RARP(反向地址解析協(xié)議ReverseAddressResolutionProtocol)確定網(wǎng)絡(luò)上一臺(tái)計(jì)算機(jī)的地址,和ARP正好相反。用戶服務(wù)BOOTP(啟動(dòng)協(xié)議BootProtocol)由網(wǎng)絡(luò)服務(wù)器上取得啟動(dòng)信息,然后將本地的網(wǎng)絡(luò)計(jì)算機(jī)啟動(dòng)。FTP(文件傳輸協(xié)議FileTransferProtocol)通過國(guó)際互連網(wǎng)從一臺(tái)計(jì)算機(jī)上傳輸一個(gè)或多個(gè)文件到另外一臺(tái)計(jì)算機(jī)。TELNET(遠(yuǎn)程登陸)允許一個(gè)遠(yuǎn)程登陸,使用者可以從網(wǎng)絡(luò)上的一臺(tái)機(jī)器通過TELNET連線到另一臺(tái)機(jī)器,就像使用者直接在本地操作一樣。EGP(外部網(wǎng)關(guān)協(xié)議ExteriorGatewayProtocol)為外部網(wǎng)絡(luò)傳輸路由信息。GGP(網(wǎng)關(guān)到網(wǎng)關(guān)協(xié)議Gateway-to-GatewayProtocol)在網(wǎng)關(guān)和網(wǎng)關(guān)之間傳輸路由協(xié)議。IGP(內(nèi)部網(wǎng)關(guān)協(xié)議InteriorGatewayProtocol)在內(nèi)部網(wǎng)絡(luò)傳輸路由信息。4.其他協(xié)議(也為網(wǎng)絡(luò)提供了重要的服務(wù))NFS(網(wǎng)絡(luò)文件系統(tǒng)NetworkFileSystem)允許將一臺(tái)機(jī)器的目錄被另一臺(tái)機(jī)器上的用戶安裝(Mount)到自己的機(jī)器上,就像是對(duì)本地文件系統(tǒng)進(jìn)行操作一樣進(jìn)行各式各樣的操作。NIS(網(wǎng)絡(luò)信息服務(wù)NetworkInformationService)對(duì)整個(gè)網(wǎng)絡(luò)用戶的用戶名、密碼進(jìn)行統(tǒng)一管理,簡(jiǎn)化在NIS服務(wù)下整個(gè)網(wǎng)絡(luò)登陸的用戶名/密碼檢查。RPC(遠(yuǎn)程過程調(diào)用RemoteProcedureCall)通過它可以允許遠(yuǎn)程的應(yīng)用程序通過簡(jiǎn)單的、有效的手段聯(lián)系本地的應(yīng)用程序,反之也是。SMTP(簡(jiǎn)單郵件傳輸協(xié)議SimpleMailTransferProtocol)一個(gè)專門為電子郵件在多臺(tái)機(jī)器中傳輸?shù)膮f(xié)議,平時(shí)發(fā)郵件的SMTP服務(wù)器提供的必然服務(wù)。SNMP(簡(jiǎn)單網(wǎng)絡(luò)管理協(xié)議SimpleNetworkManagementProtocol)這是一項(xiàng)為超級(jí)用戶準(zhǔn)備的服務(wù),超級(jí)用戶可以通過它來進(jìn)行簡(jiǎn)單的網(wǎng)絡(luò)管理。端口TCP和UDP協(xié)議是以IP協(xié)議為基礎(chǔ)的傳輸,為了方便多種應(yīng)用程序,區(qū)分不同應(yīng)用程序的數(shù)據(jù)和狀態(tài),引入了端口的概念。端口是一個(gè)16位的整數(shù)類型值,通常稱這個(gè)值為端口號(hào)。如果是服務(wù)程序,則需要對(duì)某個(gè)端口進(jìn)行綁定,這樣某個(gè)客戶端可以方位本主機(jī)上的此端口來與應(yīng)用程序進(jìn)行通信。由于IP地址只能對(duì)主機(jī)進(jìn)行區(qū)分,而加上端口號(hào)就可以對(duì)區(qū)分此主機(jī)上的應(yīng)用程序。實(shí)際上,IP地址和端口號(hào)的組合,可以確定在網(wǎng)絡(luò)上的一個(gè)程序通路,端口號(hào)實(shí)際上是操作系統(tǒng)標(biāo)識(shí)應(yīng)用程序的一種方法。主機(jī)字節(jié)序和網(wǎng)絡(luò)字節(jié)序在使用網(wǎng)絡(luò)進(jìn)行程序設(shè)計(jì)中會(huì)碰到的一個(gè)問題是字節(jié)序的問題,這在基于單機(jī)或者同類型機(jī)器進(jìn)行開發(fā)的過程中很少遇到。由于網(wǎng)絡(luò)的特點(diǎn)是將Internet上不同的網(wǎng)絡(luò)設(shè)備和主機(jī)進(jìn)行連接和通信,這決定了使用網(wǎng)絡(luò)進(jìn)行開發(fā)的程序的特點(diǎn)就是要兼容各種類型的設(shè)備,其中的數(shù)據(jù)在不同的設(shè)備上要有唯一的含義。字節(jié)序的問題是上述情況下的典型問題。字節(jié)序的含義字節(jié)序的問題是由于CPU對(duì)整數(shù)在內(nèi)存中的存放方式造成的。字節(jié)多于一個(gè)字節(jié)的數(shù)據(jù)類型在內(nèi)存中的存放順序叫主機(jī)字節(jié)序。最常見的字節(jié)序有兩種,小端字節(jié)序和大端字節(jié)序:小端字節(jié)序,即LittleEndian(簡(jiǎn)稱LE),將數(shù)據(jù)的最低字節(jié)放在內(nèi)存的起始位置。小端字節(jié)序的特點(diǎn)是內(nèi)存地址較低的位存放數(shù)據(jù)的低位,內(nèi)存地址高的位存放數(shù)據(jù)的高位,與思維的習(xí)慣。采用低字節(jié)序的CPU有x86架構(gòu)的intel系列產(chǎn)品。大端字節(jié)序,即BigEndian(簡(jiǎn)稱BE),將數(shù)據(jù)的高字節(jié)放在內(nèi)存的起始位置。大端字節(jié)序的特點(diǎn)是內(nèi)存中低字節(jié)位置存放數(shù)據(jù)的高位字節(jié),內(nèi)存中的高位字節(jié)存放數(shù)據(jù)的較低字節(jié)數(shù)據(jù),與思維習(xí)慣不一致,但是與實(shí)際數(shù)據(jù)的表達(dá)方式是一致的。采用大端字節(jié)序的CPU有PowerPC的UNIX系統(tǒng)。網(wǎng)絡(luò)字節(jié)序的轉(zhuǎn)換網(wǎng)絡(luò)的字節(jié)序標(biāo)準(zhǔn)規(guī)定為大端字節(jié)序,不同平臺(tái)上會(huì)對(duì)主機(jī)字節(jié)序進(jìn)行轉(zhuǎn)化,成為網(wǎng)絡(luò)字節(jié)序后再進(jìn)行傳送,到主機(jī)后再轉(zhuǎn)化為主機(jī)字節(jié)序,數(shù)據(jù)的傳輸就不會(huì)產(chǎn)生傳輸造成的問題了。同一個(gè)數(shù)據(jù)在不同的平臺(tái)上可以使用網(wǎng)絡(luò)字節(jié)序的轉(zhuǎn)換函數(shù)來實(shí)現(xiàn)。什么是套接字(SOCKET)套接口是對(duì)網(wǎng)絡(luò)中不同主機(jī)上應(yīng)用進(jìn)程之間進(jìn)行雙向通信的端點(diǎn)的抽象,一個(gè)套接口就是網(wǎng)絡(luò)上進(jìn)程通信的一端,提供了應(yīng)用層進(jìn)程利用網(wǎng)絡(luò)協(xié)議棧交換數(shù)據(jù)的機(jī)制。Socket的功能Socket的英文原意就是“孔”或“插座”,將電話系統(tǒng)與面向連接的Socket機(jī)制相比,有著驚人相似的地方。以一個(gè)國(guó)家級(jí)的電話網(wǎng)為例。電話的通話雙方相當(dāng)于相互通信的兩個(gè)進(jìn)程;通話雙方所在的地區(qū)(享有一個(gè)全局唯一的區(qū)號(hào))相當(dāng)于一個(gè)網(wǎng)絡(luò),區(qū)號(hào)是它的網(wǎng)絡(luò)地址;區(qū)內(nèi)的一個(gè)單位的交換機(jī)相當(dāng)于一臺(tái)主機(jī),主機(jī)分配給每個(gè)用戶的局內(nèi)號(hào)碼相當(dāng)于Socket號(hào).任何用戶在通話之前,首先要占有一部電話機(jī),相當(dāng)于申請(qǐng)一個(gè)Socket號(hào);同時(shí)要知道對(duì)方的電話號(hào)碼,相當(dāng)于對(duì)方有一個(gè)Socket。然后向?qū)Ψ綋芴?hào)呼叫,相當(dāng)于發(fā)出連接請(qǐng)求(假如對(duì)方不在同一區(qū)內(nèi),還要撥對(duì)方區(qū)號(hào),相當(dāng)于給出網(wǎng)絡(luò)地址)。對(duì)方假如在場(chǎng)并空閑(相當(dāng)于通信的另一主機(jī)開機(jī)且可以接受連接請(qǐng)求),拿起電話話筒,雙方就可以正式通話,相當(dāng)于連接成功。雙方通話的過程,是向電話機(jī)發(fā)出信號(hào)和從電話機(jī)接受信號(hào)的過程,相當(dāng)于向Socket發(fā)送數(shù)據(jù)和從Socket接受數(shù)據(jù)。通話結(jié)束后,一方掛起電話機(jī),相當(dāng)于關(guān)閉Socket,撤消連接。套接字基礎(chǔ)從套接字所處的地位來講,套接字上聯(lián)應(yīng)用進(jìn)程,下聯(lián)網(wǎng)絡(luò)協(xié)議棧,是應(yīng)用程序通過網(wǎng)絡(luò)協(xié)議棧進(jìn)行通信的接口,是應(yīng)用程序與網(wǎng)絡(luò)協(xié)議棧進(jìn)行交互的接口。套接字基礎(chǔ)(續(xù))從實(shí)現(xiàn)的角度來講,非常復(fù)雜。套接字是一個(gè)復(fù)雜的軟件機(jī)構(gòu),包含了一定的數(shù)據(jù)結(jié)構(gòu),包含許多選項(xiàng),由操作系統(tǒng)內(nèi)核管理。從使用的角度來講,非常簡(jiǎn)單。對(duì)于套接字的操作形成了一種網(wǎng)絡(luò)應(yīng)用程序的編程接口(API)。操作套接字的編程接口函數(shù)稱作套接字編程接口,套接字是它的操作對(duì)象。總之,套接字是網(wǎng)絡(luò)通信的基石。常用的socket流式套接字:它提供基于TCP協(xié)議的雙向、可靠、有序且不重復(fù)的無記錄邊界的數(shù)據(jù)流。數(shù)據(jù)報(bào)套接字:它提供基于UDP協(xié)議的雙向數(shù)據(jù)流,但不一定可靠、有序和不重復(fù)。原始套接字:它提供網(wǎng)絡(luò)下層通信協(xié)議的直接訪問。一般用于開發(fā)新的網(wǎng)絡(luò)層協(xié)議,如新的IP協(xié)議等。UDPTCP三種表示套接字地址的結(jié)構(gòu)(1).structsockaddr這個(gè)結(jié)構(gòu)用來存儲(chǔ)套接字地址。數(shù)據(jù)定義:structsockaddr{unsignedshortsa_family;/*address族,AF_xxx*/charsa_data[14];/*14bytes的協(xié)議地址*/};sa_family一般來說,都是“AF_INET”。sa_data包含了一些遠(yuǎn)程電腦的地址、端口和套接字的數(shù)目,它里面的數(shù)據(jù)是雜溶在一切的。三種表示套接字地址的結(jié)構(gòu)(續(xù))(2).structsockaddr_in為了處理structsockaddr,程序員建立了另外一個(gè)相似的結(jié)構(gòu)structsockaddr_in:structsockaddr_in(“in”
代表“Internet”)structsockaddr_in{shortintsin_family;/*Internet地址族*/unsignedshortintsin_port;/*端口號(hào)*/structin_addrsin_addr;/*Internet地址*/unsignedcharsin_zero[8];/*添0(和structsockaddr一樣大?。?/};這個(gè)結(jié)構(gòu)提供了方便的手段來訪問socketaddress(structsockaddr)結(jié)構(gòu)中的每一個(gè)元素。三種表示套接字地址的結(jié)構(gòu)(續(xù))(3).structin_addr專門用來存儲(chǔ)IP地址,其定義如下:/*因特網(wǎng)地址(astructureforhistoricalreasons)*/structin_addr{unsignedlongs_addr;};如果你聲明了一個(gè)“
ina”
作為一個(gè)structsockaddr_in的結(jié)構(gòu),
那么“ina.sin_addr.s_addr”就是4個(gè)字節(jié)的IP地址(按網(wǎng)絡(luò)字節(jié)順序排放)。需要注意的是,即使你的系統(tǒng)仍然使用聯(lián)合而不是結(jié)構(gòu)來表示structin_addr,你仍然可以用上面的方法得到4個(gè)字節(jié)的IP地址.三種表示套接字地址的結(jié)構(gòu)(續(xù))(4).這些數(shù)據(jù)結(jié)構(gòu)的一般用法:首先,定義一個(gè)Sockaddr_in的結(jié)構(gòu)實(shí)例,并將它清零。比如:structsockaddr_inmyad;memset(&myad,0,sizeof(structsockaddr_in));然后,為這個(gè)結(jié)構(gòu)賦值,比如:myad.sin_family=AF_INET;myad.sin_port=htons(8080);myad.sin_addr.s_addr=htonl(INADDR-ANY);第三步:在函數(shù)調(diào)用中使用時(shí),將這個(gè)結(jié)構(gòu)強(qiáng)制轉(zhuǎn)換為sockaddr類型。如:accept(listenfd,(sockaddr*)(&myad),&addrlen);本機(jī)字節(jié)順序和網(wǎng)絡(luò)字節(jié)順序在具體計(jì)算機(jī)中的多字節(jié)數(shù)據(jù)的存儲(chǔ)順序,稱為本機(jī)字節(jié)順序。多字節(jié)數(shù)據(jù)在網(wǎng)絡(luò)協(xié)議報(bào)頭中的存儲(chǔ)順序,稱為網(wǎng)絡(luò)字節(jié)順序。在網(wǎng)絡(luò)上面有著許多類型的機(jī)器,這些機(jī)器在表示數(shù)據(jù)的字節(jié)順序是不同的,比如i386芯片是低字節(jié)在內(nèi)存地址的低端,高字節(jié)在高端,而alpha芯片卻相反.為了統(tǒng)一起來,在Linux下面,有專門的字節(jié)轉(zhuǎn)換函數(shù).unsignedlonginthtonl(unsignedlonginthostlong)
unsignedshortinthtons(unisgnedshortinthostshort)
unsignedlongintntohl(unsignedlongintnetlong)
unsignedshortintntohs(unsignedshortintnetshort)在這四個(gè)轉(zhuǎn)換函數(shù)中,h代表host,n代表network.s代表shortl代表long第一個(gè)函數(shù)的意義是將本機(jī)器上的long數(shù)據(jù)轉(zhuǎn)化為網(wǎng)絡(luò)上的long.其他幾個(gè)函數(shù)的意義也差不多.點(diǎn)分十進(jìn)制的IP地址的轉(zhuǎn)換(1)inet_aton將strptr所指的字符串轉(zhuǎn)換成32位的網(wǎng)絡(luò)字節(jié)序二進(jìn)制值。
#include<arpa/inet.h> intinet_aton(constchar*strptr,structin_addr*addrptr);(2)inet_addr功能同上,返回地址。int_addr_tinet_addr(constchar*strptr);(3)inet_ntoa將32位網(wǎng)絡(luò)字節(jié)序二進(jìn)制地址轉(zhuǎn)換成點(diǎn)分十進(jìn)制的串。char*inet_ntoa(stuctin_addrinaddr);域名服務(wù)在網(wǎng)絡(luò)上標(biāo)志一臺(tái)機(jī)器可以用IP或者是用域名.那么我們?cè)趺慈ミM(jìn)行轉(zhuǎn)換呢?
struct
hostent
*gethostbyname(const
char
*hostname)可以將機(jī)器名(如
)轉(zhuǎn)換為一個(gè)結(jié)構(gòu)指針.在這個(gè)結(jié)構(gòu)里面儲(chǔ)存了域名的信息
struct
hostent
*gethostbyaddr(const
char
*addr,int
len,int
type)可以將一個(gè)32位的IP地址(C0A80001)轉(zhuǎn)換為結(jié)構(gòu)指針.
這兩個(gè)函數(shù)失敗時(shí)返回NULL
且設(shè)置h_errno錯(cuò)誤變量,調(diào)用h_strerror()可以得到詳細(xì)的出錯(cuò)信息
struct
hostent的定義:
struct
hostent{
char
*h_name;
/*
主機(jī)的正式名稱
*/
char
*h_aliases;
/*
主機(jī)的別名
*/
int
h_addrtype;
/*
主機(jī)的地址類型
AF_INET*/
int
h_length;
/*
主機(jī)的地址長(zhǎng)度
對(duì)于IP4
是4字節(jié)32位*/
char
**h_addr_list;
/*
主機(jī)的IP地址列表
*/
}
#define
h_addr
h_addr_list[0]
/*
主機(jī)的第一個(gè)IP地址*/套接字的工作過程初等網(wǎng)絡(luò)函數(shù)1socket#include<sys/socket.h>intsocket(intdomain,inttype,intprotocol)socket為網(wǎng)絡(luò)通訊做基本的準(zhǔn)備.成功時(shí)返回文件描述符,失敗時(shí)返回-1。通過errno可知道出錯(cuò)的詳細(xì)情況.參數(shù)說明:domain:說明我們網(wǎng)絡(luò)程序所在的主機(jī)采用的通訊協(xié)族(AF_UNIX和AF_INET等)。AF_UNIX只能夠用于單一的Unix系統(tǒng)進(jìn)程間通信,而AF_INET是針對(duì)Internet的,因而可以允許在遠(yuǎn)程主機(jī)之間通信當(dāng)我們
mansocket時(shí)發(fā)現(xiàn)
domain可選項(xiàng)是
PF_*而不是AF_*,因?yàn)間libc是posix的實(shí)現(xiàn)
所以用PF代替了AF,不過我們都可以使用的.type:我們網(wǎng)絡(luò)程序所采用的通訊協(xié)議。SOCK_STREAM表明我們用的是TCP協(xié)議,這樣會(huì)提供按順序的,可靠,雙向,面向連接的比特流.SOCK_DGRAM表明我們用的是UDP協(xié)議,這樣只會(huì)提供定長(zhǎng)的,不可靠,無連接的通信。
SOCK_RAW原始套接字,用來直接訪問IP協(xié)議。protocol:由于我們指定了type,所以這個(gè)地方我們一般只要用0來代替就可以了。初等網(wǎng)絡(luò)函數(shù)(續(xù))2bindintbind(intsockfd,structsockaddr*my_addr,intaddrlen)bind將本地的端口同socket返回的文件描述符捆綁在一起.成功是返回0,失敗的情況和socket一樣。參數(shù)說明sockfd:是由socket調(diào)用返回的文件描述符.addrlen:是sockaddr結(jié)構(gòu)的長(zhǎng)度.my_addr:是一個(gè)指向sockaddr的指針.構(gòu)造套接字地址舉例intlistenfd;structsockaddr_inserver_addr;listenfd=socket(AF_INET,SOCK_STREAM,0);bzero(&server_addr,sizeof(server_addr));server_addr.sin_family=AF_INET;server_addr.sin_port=htons(80);inet_pton(AF_INET,“44”,&server_addr.sin_addr);bind(listenfd,&server_addr,sizeof(structsockaddr_in))初等網(wǎng)絡(luò)函數(shù)(續(xù))3listenintlisten(intsockfd,intbacklog)listen函數(shù)將bind的文件描述符變?yōu)楸O(jiān)聽套接字。返回的情況和bind一樣。參數(shù)說明sockfd:是bind后的文件描述符.。backlog:設(shè)置請(qǐng)求排隊(duì)的最大長(zhǎng)度.當(dāng)有多個(gè)客戶端程序和服務(wù)端相連時(shí),使用這個(gè)表示可以介紹的排隊(duì)長(zhǎng)度。初等網(wǎng)絡(luò)函數(shù)(續(xù))4acceptintaccept(intsockfd,structsockaddr*addr,int*addrlen)accept成功時(shí)返回最后的服務(wù)器端的文件描述符,這個(gè)時(shí)候服務(wù)器端可以向該描述符寫信息了。失敗時(shí)返回-1。參數(shù)說明sockfd:是listen后的文件描述符.。addr,addrlen是用來給客戶端的程序填寫的,服務(wù)器端只要傳遞指針就可以了.。bind,listen和accept是服務(wù)器端用的函數(shù),accept調(diào)用時(shí),服務(wù)器端的程序會(huì)一直阻塞到有一個(gè)
客戶程序發(fā)出了連接,
accept成功時(shí)返回最后的服務(wù)器端的文件描述符。初等網(wǎng)絡(luò)函數(shù)(續(xù))5connectintconnect(intsockfd,structsockaddr*serv_addr,intaddrlen)connect函數(shù)是客戶端用來同服務(wù)端連接的。成功時(shí)返回0,sockfd是同服務(wù)端通訊的文件描述符
。失敗時(shí)返回-1。參數(shù)說明sockfd:socket返回的文件描述符.serv_addr:儲(chǔ)存了服務(wù)器端的連接信息.其中sin_add是服務(wù)端的地址
addrlen:serv_addr的長(zhǎng)度
完整的讀寫函數(shù)一旦我們建立了連接,我們的下一步就是進(jìn)行通信了.在Linux下面把我們前面建立的通道
看成是文件描述符,這樣服務(wù)器端和客戶端進(jìn)行通信時(shí)候,只要往文件描述符里面讀寫東西了.就象我們往文件讀寫一樣。1寫函數(shù)writessize_twrite(intfd,constvoid*buf,size_tnbytes)
write函數(shù)將buf中的nbytes字節(jié)內(nèi)容寫入文件描述符fd.成功時(shí)返回寫的字節(jié)數(shù).失敗時(shí)返回-1.并設(shè)置errno變量.在網(wǎng)絡(luò)程序中,當(dāng)我們向套接字文件描述符寫時(shí)有倆種可能.1)write的返回值大于0,表示寫了部分或者是全部的數(shù)據(jù).2)返回的值小于0,此時(shí)出現(xiàn)了錯(cuò)誤.我們要根據(jù)錯(cuò)誤類型來處理.如果錯(cuò)誤為EINTR表示在寫的時(shí)候出現(xiàn)了中斷錯(cuò)誤.如果為EPIPE表示網(wǎng)絡(luò)連接出現(xiàn)了問題(對(duì)方已經(jīng)關(guān)閉了連接).寫實(shí)例intmy_write(intfd,void*buffer,intlength)
{intbytes_left;
intwritten_bytes;
char*ptr;
ptr=buffer;
bytes_left=length;
while(bytes_left>0){/*開始寫*/
written_bytes=write(fd,ptr,bytes_left);
if(written_bytes<=0){/*出錯(cuò)了*/
if(errno==EINTR)/*中斷錯(cuò)誤我們繼續(xù)寫*/
written_bytes=0;
else/*其他錯(cuò)誤沒有辦法,只好撤退了*/
return(-1);
}
bytes_left-=written_bytes;
ptr+=written_bytes;/*從剩下的地方繼續(xù)寫*/
}
return(0);
}完整的讀寫函數(shù)(續(xù))2讀函數(shù)readssize_tread(intfd,void*buf,size_tnbyte)read函數(shù)是負(fù)責(zé)從fd中讀取內(nèi)容.當(dāng)讀成功時(shí),read返回實(shí)際所讀的字節(jié)數(shù),如果返回的值是0表示已經(jīng)讀到文件的結(jié)束了,小于0表示出現(xiàn)了錯(cuò)誤.讀實(shí)例如果錯(cuò)誤為EINTR說明讀是由中斷引起的,如果是ECONNREST表示網(wǎng)絡(luò)連接出了問題.和上面一樣,我們也寫一個(gè)自己的讀函數(shù).intmy_read(intfd,void*buffer,intlength)
{
intbytes_left;
intbytes_read;
char*ptr;
bytes_left=length;
while(bytes_left>0)
{
bytes_read=read(fd,ptr,bytes_read);
if(bytes_read<0)
{if(errno==EINTR)
bytes_read=0;
else
return(-1);
}
else
if(bytes_read==0)break;
bytes_left-=bytes_read;
ptr+=bytes_read;
}
return(length-bytes_left);
}完整的讀寫函數(shù)(續(xù))3數(shù)據(jù)的傳遞
有了上面的兩個(gè)函數(shù),我們就可以向客戶端或者是服務(wù)端傳遞數(shù)據(jù)了.比如我們要傳遞一個(gè)結(jié)構(gòu).可以使用如下方式
:/*客戶端向服務(wù)端寫*/
structmy_structmy_struct_client;
write(fd,(void*)&my_struct_client,sizeof(structmy_struct);/*服務(wù)端的讀*/
charbuffer[sizeof(structmy_struct)];
struct*my_struct_server;
read(fd,(void*)buffer,sizeof(structmy_struct));
my_struct_server=(structmy_struct*)buffer;在網(wǎng)絡(luò)上傳遞數(shù)據(jù)時(shí)我們一般都是把數(shù)據(jù)轉(zhuǎn)化為char類型的數(shù)據(jù)傳遞.接收的時(shí)候也是一樣的。注意的是我們沒有必要在網(wǎng)絡(luò)上傳遞指針(因?yàn)閭鬟f指針是沒有任何意義的,我們必須傳遞指針?biāo)赶虻膬?nèi)容)。面向連接的傳輸層套接字舉例服務(wù)器端程序/*******服務(wù)器程序(server.c)********/
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<netdb.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<sys/socket.h>
intmain(intargc,char*argv[])
{intsockfd,new_fd;
structsockaddr_inserver_addr;
structsockaddr_inclient_addr;
intsin_size,portnumber;
charhello[]="Hello!AreYouFine?\n";
if(argc!=2){
fprintf(stderr,"Usage:%sportnumber\a\n",argv[0]);
exit(1);
}
if((portnumber=atoi(argv[1]))<0){
fprintf(stderr,"Usage:%sportnumber\a\n",argv[0]);
exit(1);
}/*服務(wù)器端開始建立socket描述符*/if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
{fprintf(stderr,"Socketerror:%s\n\a",strerror(errno));
exit(1);
}/*服務(wù)器端填充sockaddr結(jié)構(gòu)*/
bzero(&server_addr,sizeof(structsockaddr_in));server_addr.sin_family=AF_INET;server_addr.sin_addr.s_addr=htonl(INADDR_ANY);server_addr.sin_port=htons(portnumber);/*捆綁sockfd描述符*/
if(bind(sockfd,(structsockaddr*)(&server_addr),sizeof(structsockaddr))==-1){fprintf(stderr,"Binderror:%s\n\a",strerror(errno));
exit(1);
}/*監(jiān)聽sockfd描述符*/
if(listen(sockfd,5)==-1)
{fprintf(stderr,"Listenerror:%s\n\a",strerror(errno));
exit(1);
}while(1){/*服務(wù)器阻塞,直到客戶程序建立連接*/
sin_size=sizeof(structsockaddr_in);
if((new_fd=accept(sockfd,(structsockaddr*)(&client_addr),&sin_size))==-1){
fprintf(stderr,"Accepterror:%s\n\a",strerror(errno));
exit(1);
}
fprintf(stderr,“Servergetconnectionfrom%s\n”,inet_ntoa(client_addr.sin_addr));
if(write(new_fd,hello,strlen(hello))==-1){
fprintf(stderr,“WriteError:%s\n”,strerror(errno));
exit(1);
}/*這個(gè)通訊已經(jīng)結(jié)束*/
close(new_fd);/*循環(huán)下一個(gè)*/
}
close(sockfd);
exit(0);
}面向連接的傳輸層套接字舉例客戶端程序/*******客戶端程序client.c**********/
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<netdb.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<sys/socket.h>
intmain(intargc,char*argv[])
{intsockfd;
charbuffer[1024];
structsockaddr_inserver_addr;
structhostent*host;
intportnumber,nbytes;
if(argc!=3){
fprintf(stderr,"Usage:%shostnameportnumber\a\n",argv[0]);
exit(1);
}
if((host=gethostbyname(argv[1]))==NULL)
{fprintf(stderr,"Gethostnameerror\n");
exit(1);
}
if((portnumber=atoi(argv[2]))<0)
{fprintf(stderr,"Usage:%shostnameportnumber\a\n",argv[0]);
exit(1);
}/*客戶程序開始建立sockfd描述符*/
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1){
fprintf(stderr,"SocketError:%s\a\n",strerror(errno));
exit(1);}/*客戶程序填充服務(wù)端的資料*/
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(portnumber);
server_addr.sin_addr=*((structin_addr*)host->h_addr);/*客戶程序發(fā)起連接請(qǐng)求*/
if(connect(sockfd,(structsockaddr*)(&server_addr),sizeof(structsockaddr))==-1)
{fprintf(stderr,"ConnectError:%s\a\n",strerror(errno));
exit(1);}/*連接成功了*/
if((nbytes=read(sockfd,buffer,1024))==-1){
fprintf(stderr,"ReadError:%s\n",strerror(errno));
exit(1);
}
buffer[nbytes]='\0';
printf("Ihavereceived:%s\n",buffer);/*結(jié)束通訊*/
close(sockfd);
exit(0);
}無連接的套接字編程使用數(shù)據(jù)報(bào)套接字開發(fā)網(wǎng)絡(luò)應(yīng)用程序,既可以采用客戶/服務(wù)器模式,也可以采用對(duì)等模式??蛻?服務(wù)器模式UDP通信機(jī)制在服務(wù)器端服務(wù)器先使用AF_INET協(xié)議族創(chuàng)建UDP數(shù)據(jù)報(bào)類型的套接字,該socket類型為SOCK_DGRAM;然后服務(wù)器調(diào)用bind函數(shù),給此UDP套接字綁定一個(gè)端口;調(diào)用recvfrom函數(shù)在指定的端口上等待客戶端發(fā)送來的UDP數(shù)據(jù)報(bào)。在客戶端先通過socket函數(shù)創(chuàng)建一個(gè)數(shù)據(jù)報(bào)套接字;然后由操作系統(tǒng)為這個(gè)套接字分配端口號(hào);此后客戶端就可以使用sendto函數(shù)向一個(gè)指定的地址發(fā)送一個(gè)UDP套接字。在服務(wù)器端收到套接字后,從recvfrom中返回,在對(duì)數(shù)據(jù)進(jìn)行處理之后,再用sendto函數(shù)處理的結(jié)果返回客戶端。UDP與TCP的比較UDP服務(wù)器通常是非連接的因而UDP服務(wù)器進(jìn)程不需要象TCP服務(wù)器那樣在傾聽套接字上接收新建的連接;UDP只需要在綁定的端口上等待客戶機(jī)發(fā)送來的UDP數(shù)據(jù)報(bào),并對(duì)其進(jìn)行處理和響應(yīng)。一個(gè)TCP服務(wù)器進(jìn)程只有在完成了對(duì)某客戶機(jī)的服務(wù)后,才能為其他的客戶機(jī)提供服務(wù);UDP客戶機(jī)并不獨(dú)占服務(wù)器,UDP服務(wù)器只是接收數(shù)據(jù)報(bào),處理并返回結(jié)果。UDP的應(yīng)用場(chǎng)合UDP支持廣播和多播。如果要使用廣播和多播,必須使用UDP套接字。UDP套接字沒有連接的建立和終止過程。UDP只需要兩個(gè)分組來交換一個(gè)請(qǐng)求和應(yīng)答。UDP不適合海量數(shù)據(jù)的傳輸。無連接的傳輸層套接字
兩個(gè)常用的函數(shù)
#include<sys/socket.h>intrecvfrom(intsockfd,void*buf,intlen,unsignedintflags,structsockaddr*fromint*fromlen)intsendto(intsockfd,constvoid*msg,intlen,unsignedintflags,structsockaddr*tointtolen)sockfd,buf,len的意義和read,write一樣,分別表示套接字描述符,發(fā)送或接收的緩沖區(qū)及大小recvfrom負(fù)責(zé)從sockfd接收數(shù)據(jù),如果from不是NULL,那么在from里面存儲(chǔ)了信息來源的情況,如果對(duì)信息的來源不感興趣,可以將from和fromlen設(shè)置為NULL.sendto負(fù)責(zé)向to發(fā)送信息.此時(shí)在to里面存儲(chǔ)了收信息方的詳細(xì)資料.UDP實(shí)例一個(gè)實(shí)例程序編譯好后,運(yùn)行時(shí)需指定雙方所使用的IP地址和端口號(hào),第一個(gè)參數(shù)是對(duì)方的IP地址,然后是對(duì)方的端口號(hào),之后是本端的IP地址和端口號(hào)。例如在test1的終端輸入:a.out004321685678同時(shí)在test2上輸入:a.out685678004321然后雙方都可以發(fā)送信息給對(duì)方了/*firststepinudpprogramming*/#include<sys/types.h>#include<sys/socket.h>#include<arpa/inet.h>#include<stdio.h>#defineBUFLEN255intmain(intargc,char**argv){ structsockaddr_inpeeraddr,localaddr; intsockfd; charrecmsg[BUFLEN+1]; intsocklen,n; if(argc!=5){ printf("%s<destIPaddress><destport><sourceIPaddress><sourceport>\n",argv[0]); exit(0); }sockfd=socket(AF_INET,SOCK_DGRAM,0); if(sockfd<0){ fprintf(stderr,"socketcreatingerrorinudptalk.c!\n"); exit(1); } socklen=sizeof(structsockaddr_in); memset(&peeraddr,0,socklen); peeraddr.sin_family=AF_INET; peeraddr.sin_port=htons(atoi(argv[2])); if(inet_pton(AF_INET,argv[1],&peeraddr.sin_addr)<=0){ printf("WrongdestIPaddress!\n"); exit(0); }
memset(&localaddr,0,socklen); localaddr.sin_family=AF_INET; localaddr.sin_port=htons(atoi(argv[4]));
if(inet_pton(AF_INET,argv[3],&localaddr.sin_addr)<=0){ printf("WrongsourceIPaddress!\n"); exit(0); }
if(bind(sockfd,&localaddr,socklen)<0){ fprintf(stderr,"bindlocaladdresserrorinudptalk.c!\n"); exit(2); } if(fgets(recmsg,BUFLEN,stdin)==NULL)exit(0);
if(sendto(sockfd,recmsg,strlen(recmsg),0,&peeraddr,socklen)<0){ fprintf(stderr,"sendtoerrorinudptalk.c!\n"); perror(""); exit(3);
}for(;;){ n=recvfrom(sockfd,recmsg,BUFLEN,0,&peeraddr,&socklen); if(n<0){ fprintf(stderr,"recvfromerrorinudptalk.c\n"); perror(""); exit(4); } else{ recmsg[n]=0; printf("peer:%s",recmsg); }
if(fgets(recmsg,BUFLEN,stdin)==NULL) exit(0); if(sendto(sockfd,recmsg,strlen(recmsg),0,&peeraddr,socklen)<0){ fprintf(stderr,"sendtoerrorinudptalk.c!\n"); perror(""); exit(3); }}}對(duì)第一個(gè)UDP例程的思考思考:1.只有來自對(duì)方IP和端口號(hào)的數(shù)據(jù)報(bào)才予以處理,如何過濾掉其它數(shù)據(jù)報(bào)?2.雙方發(fā)送和接收交替進(jìn)行,只要有一方發(fā)出數(shù)據(jù)報(bào),對(duì)方阻塞的狀態(tài)就能消除。如果一個(gè)數(shù)據(jù)報(bào)丟失,通信雙方都在recvfrom中阻塞,永遠(yuǎn)等待。超時(shí)機(jī)制的設(shè)置?對(duì)第一個(gè)UDP例程的思考解決第一個(gè)問題:接收數(shù)據(jù)后,加入對(duì)數(shù)據(jù)報(bào)地址的檢驗(yàn):
if(memcmp(recvaddr,perraddr,socklen)!=0)
continue;這樣就將來自其他地址的數(shù)據(jù)報(bào)拒之門外了。對(duì)第一個(gè)UDP例程的思考解決第二個(gè)問題:前面提到的sock選項(xiàng)SO_RCVTIMEO就可以完成阻塞超時(shí)的設(shè)置。在程序中加入:#include<sys/time.h>Structtimevalrecto;Inttolen=sizeof(structtimeval);…/*建立socket等操作*/rcvto.tv_sec=3;/*這兩句對(duì)rcvto定時(shí)為3秒0毫秒*/rccvto.tv_usec=0;Setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,&rcvto,tolen);getsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,&rcvto,&tolen);Printf(“receivetimeoutsettedis%ldsecond%ldmillisecond\n”,rcvto.tv_sec,rcvto.tv_usec);如果顯示Receivetimeoutsettedis3second0millisecond,那么就設(shè)置成功了;如果結(jié)果是Receivetimeoutsettedis0second0millisecond,就意味著超時(shí)時(shí)間為無窮大。設(shè)置了SO_RCVTIMEO,那么在發(fā)生超時(shí)后,recvfrom將返回,返回值為-1,同時(shí)errno被置為EWOULDBLOCK。高級(jí)套接字函數(shù)1、recv和sendrecv和send函數(shù)提供了和read和write差不多的功能。不過它們提供了第四個(gè)參數(shù)來控制讀寫操作。intrecv(intsockfd,void*buf,intlen,intflags)intsend(intsockfd,void*buf,intlen,intflags)前面的三個(gè)參數(shù)和read,write一樣,第四個(gè)參數(shù)可以是0或者是以下的組合:MSG_DONTROUTE不查找路由表MSG_OOB接受或者發(fā)送帶外數(shù)據(jù)MSG_PEEK查看數(shù)據(jù),并不從系統(tǒng)緩沖區(qū)移走數(shù)據(jù)MSG_WAITALL等待所有數(shù)據(jù)MSG_DONTROUTE:是send函數(shù)使用的標(biāo)志。這個(gè)標(biāo)志告訴IP協(xié)議,目的主機(jī)在本地網(wǎng)絡(luò)上面,沒有必要查找路由表。這個(gè)標(biāo)志一般用網(wǎng)絡(luò)診斷和路由程序里面。
MSG_OOB:表示可以接收和發(fā)送帶外的數(shù)據(jù)。關(guān)于帶外數(shù)據(jù)我們以后會(huì)解釋的。MSG_PEEK:是recv函數(shù)的使用標(biāo)志。表示只是從系統(tǒng)緩沖區(qū)中讀取內(nèi)容,而不清楚系統(tǒng)緩沖區(qū)的內(nèi)容。這樣下次讀的時(shí)候,仍然是一樣的內(nèi)容。一般在有多個(gè)進(jìn)程讀寫數(shù)據(jù)時(shí)可以使用這個(gè)標(biāo)志。MSG_WAITALL:是recv函數(shù)的使用標(biāo)志。表示等到所有的信息到達(dá)時(shí)才返回。使用這個(gè)標(biāo)志的時(shí)候recv回一直阻塞,直到指定的條件滿足,或者是發(fā)生了錯(cuò)誤。
1)當(dāng)讀到了指定的字節(jié)時(shí),函數(shù)正常返回.返回值等于len。
2)當(dāng)讀到了文件的結(jié)尾時(shí),函數(shù)正常返回,返回值小于len。3)當(dāng)操作發(fā)生錯(cuò)誤時(shí),返回-1,且設(shè)置錯(cuò)誤為相應(yīng)的錯(cuò)誤號(hào)(errno)。如果flags為0,則和read,write一樣的操作。高級(jí)套接字函數(shù)(續(xù))recvmsg和sendmsgrecvmsg和sendmsg可以實(shí)現(xiàn)前面所有的讀寫函數(shù)的功能。
intrecvmsg(intsockfd,structmsghdr*msg,intflags)
intsendmsg(intsockfd,structmsghdr*msg,intflags)structmsghdr{
void*msg_name;
intmsg_namelen;
structiovec*msg_iov;
intmsg_iovlen;
void*msg_control;
intmsg_controllen;
intmsg_flags;
}structiovec{
void*iov_base;/*緩沖區(qū)開始的地址*/
size_tiov_len;/*緩沖區(qū)的長(zhǎng)度*/
}msg_name和msg_namelen當(dāng)套接字是非面向連接時(shí)(UDP),它們存儲(chǔ)接收和發(fā)送方的地址信息。msg_name實(shí)際上是一個(gè)指向structsockaddr的指針,msg_name是結(jié)構(gòu)的長(zhǎng)度。當(dāng)套接字是面向連接時(shí),這兩個(gè)值應(yīng)設(shè)為NULLmsg_iov和msg_iovlen指出接受和發(fā)送的緩沖區(qū)內(nèi)容。msg_iov是一個(gè)結(jié)構(gòu)指針,msg_iovlen指出這個(gè)結(jié)構(gòu)數(shù)組的大小。msg_control和msg_controllen這兩個(gè)變量是用來接收和發(fā)送控制數(shù)據(jù)時(shí)的msg_flags指定接受和發(fā)送的操作選項(xiàng)。(和recv,send的選項(xiàng)一樣)高級(jí)套接字函數(shù)(續(xù))套接字的關(guān)閉關(guān)閉套接字有兩個(gè)函數(shù):
close
shutdown用close時(shí)和我們關(guān)閉文件一樣。shutdownintshutdown(intsockfd,inthowto)TCP連接是雙向的(是可讀寫的),當(dāng)我們使用close時(shí),會(huì)把讀寫通道都關(guān)閉,有時(shí)侯我們希望只關(guān)閉一個(gè)方向,這個(gè)時(shí)候我們可以使用shutdown。針對(duì)不同的howto,系統(tǒng)回采取不同的關(guān)閉方式。shutdownintshutdown(intsockfd,inthowto)TCP連接是雙向的(是可讀寫的),當(dāng)我們使用close時(shí),會(huì)把讀寫通道都關(guān)閉,有時(shí)侯我們希望只關(guān)閉一個(gè)方向,這個(gè)時(shí)候我們可以使用shutdown。針對(duì)不同的howto,系統(tǒng)回采取不同的關(guān)閉方式。系統(tǒng)為我們提供了獲取和修改套接字結(jié)構(gòu)中一些屬性的函數(shù),通過修改這些屬性,我們可以調(diào)整套接字的性能,進(jìn)而調(diào)整某些應(yīng)用程序的性能。套接字選項(xiàng)1getsockopt和setsockoptintgetsockopt(intsockfd,intlevel,intoptname,void*optval,socklen_t*optlen)
intsetsockopt(intsockfd,intlevel,intoptname,constvoid*optval,socklen_t*optlen)
level指定控制套接字的層次.可以取三種值:
1)SOL_SOCKET:通用套接字選項(xiàng).
2)IPPROTO_IP:IP選項(xiàng).
3)IPPROTO_TCP:TCP選項(xiàng).optname指定控制的方式(選項(xiàng)的名稱)。optval獲得或者是設(shè)置套接字選項(xiàng).根據(jù)選項(xiàng)名稱的數(shù)據(jù)類型進(jìn)行轉(zhuǎn)換。選項(xiàng)名稱說明數(shù)據(jù)類型=======================================================
SOL_SOCKET
----------------------------------------------------------------------------------------------
SO_BROADCAST允許發(fā)送廣播數(shù)據(jù)int
SO_DEBUG允許調(diào)試int
SO_DONTROUTE不查找路由int
SO_ERROR獲得套接字錯(cuò)誤int
SO_KEEPALIVE保持連接int
SO_LINGER延遲關(guān)閉連接structlinger
SO_OOBINLINE帶外數(shù)據(jù)放入正常數(shù)據(jù)流int
SO_RCVBUF接收緩沖區(qū)大小int
SO_SNDBUF發(fā)送緩沖區(qū)大小int
SO_RCVLOWAT接收緩沖區(qū)下限int
SO_SNDLOWAT發(fā)送緩沖區(qū)下限int
SO_RCVTIMEO接收超時(shí)structtimeval
SO_SNDTIMEO發(fā)送超時(shí)structtimeval
SO_REUSERADDR允許重用本地地址和端口int
SO_TYPE獲得套接字類型int
SO_BSDCOMPAT與BSD系統(tǒng)兼容int
==========================================================================================================IPPROTO_IP--------------------------------------------------------------------------IP_HDRINCL在數(shù)據(jù)包中包含IP首部intIP_OPTINOSIP首部選項(xiàng)intIP_TOS服務(wù)類型
IP_TTL生存時(shí)間int===================================================IPPRO_TCP--------------------------------------------------------------------------TCP_MAXSEGTCP最大數(shù)據(jù)段的大小intTCP_NODELAY不使用Nagle算法int===================================================套接字選項(xiàng)(續(xù))2ioctlioctl可以控制所有的文件描述符的情況,這里介紹一下控制套接字的選項(xiàng).定義格式:#include<unistd.h>intioctl(intfd,longcmd,unsignedlong*argp);參數(shù):fd是需要操作的套接字描述符;cmd是屬性類別;argp是屬性的參數(shù)。詳細(xì)的選項(xiàng)請(qǐng)用manioctl_list查看.===========================================iiioctl的控制選項(xiàng)--------------------------------------------------------------------------SIOCATMARK是否到達(dá)帶外標(biāo)記intFIOASYNC異步輸入/輸出標(biāo)志intFIONREAD緩沖區(qū)可讀的字節(jié)數(shù)int===========================================套接字選項(xiàng)(續(xù))3、fcntl定義格式:#include<fcntl.h>Intfcntl(intfd,intcmd,longarg);參數(shù):fd是需要操作的套接字描述符;cmd是屬性類別,cmd可以是如下值:F_SETFL:arg為O_NONBLOCK時(shí)進(jìn)入非阻塞模式,為0是進(jìn)入阻塞模式;F_GETFL:獲得屬性;F_SETOWN:用來設(shè)置套接字屬主,用來接收數(shù)據(jù)SIGIO和SIGURG;F_GETOWN:用來獲得上面設(shè)置的套接字屬主信息。系統(tǒng)IO與服務(wù)器模型
在Linux/UNIX下,有主要有4種I/O模型:阻塞I/O:最常用、最簡(jiǎn)單、效率最低非
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 成人就業(yè)協(xié)議書合同
- 裝修安全合同協(xié)議書
- 手機(jī)購(gòu)銷合同協(xié)議書
- 裝修合同簡(jiǎn)單協(xié)議書
- 商品購(gòu)買合同協(xié)議書
- 豬肉銷售合同協(xié)議書
- 協(xié)議書合同怎么寫
- 稅費(fèi)合同協(xié)議書模板
- 搞笑分手合同協(xié)議書
- 接手合同轉(zhuǎn)讓協(xié)議書
- 建筑企業(yè)材料成本管理
- 人衛(wèi)官方預(yù)防醫(yī)學(xué)課件下載
- 《雷達(dá)干擾技術(shù)概述》課件
- 中韓勞動(dòng)法比較研究
- 大學(xué)禮儀操活動(dòng)方案
- 舞蹈活動(dòng)費(fèi)用方案模板
- 比賽對(duì)陣表模板
- 電子競(jìng)技員技能理論考試復(fù)習(xí)題庫(含答案)
- 博物館保安服務(wù)投標(biāo)方案
- (完整版)煤礦技術(shù)員考試試題
- 思想道德與法治2023版教學(xué)設(shè)計(jì)第六章 學(xué)習(xí)法治思想 提升法治素養(yǎng)
評(píng)論
0/150
提交評(píng)論