版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、第六章-Linux網(wǎng)絡程序設計基本要求n1、了解TCP/IP基礎知識,什么是socket,socket編程,遠程過程調用。n2、掌握Linux平臺數(shù)據(jù)結構的傳送方法。TCP/IP協(xié)議概述nOSI參考模型與TCP/IP參考模型應用層表示層會話層傳輸層網(wǎng)絡層數(shù)據(jù)鏈路層物理層應用層傳輸層網(wǎng)絡層網(wǎng)絡接口層OSI參考模型TCP/IP參考模型OSI參考模型與TCP/IP參考模型對應關系TCP/IP協(xié)議族TCP/IP 實際上一個一起工作的通信家族,為網(wǎng)際數(shù)據(jù)通信提供通路。為討論方便可將TCP/IP 協(xié)議組大體上分為三部分:1Internet 協(xié)議(IP)2傳輸控制協(xié)議(TCP)和用戶數(shù)據(jù)報文協(xié)議(UDP)3
2、處于TCP 和UDP 之上的一組協(xié)議專門開發(fā)的應用程序。它們包括:TELNET,文件傳送協(xié)議(FTP),域名服務(DNS)和簡單的郵件傳送程序(SMTP)等許多協(xié)議。網(wǎng)絡層n第一部分也稱為網(wǎng)絡層。包括Internet 協(xié)議(IP)、網(wǎng)際控制報文協(xié)議(ICMP)和地址識別協(xié)議(ARP).n Internet 協(xié)議(IP)。n該協(xié)議被設計成互聯(lián)分組交換通信網(wǎng),以形成一個網(wǎng)際通信環(huán)境。它負責在源主機和目的地主機之間傳輸來自其較高層軟件的稱為數(shù)據(jù)報文的數(shù)據(jù)塊,它在源和目的地之間提供非連接型傳遞服務。n 網(wǎng)際控制報文協(xié)議(ICMP)。n它實際上不是IP層部分,但直接同IP層一起工作,報告網(wǎng)絡上的某些出錯
3、情況。允許網(wǎng)際路由器傳輸差錯信息或測試報文。n 地址識別協(xié)議(ARP)。nARP 實際上不是網(wǎng)絡層部分,它處于IP和數(shù)據(jù)鏈路層之間,它是在32位IP地址和48位局域網(wǎng)物理地址之間執(zhí)行翻譯的協(xié)議。傳輸層協(xié)議n 第二部分是傳輸層協(xié)議。包括傳輸控制協(xié)議和用戶數(shù)據(jù)報文協(xié)議。n 傳輸控制協(xié)議(TCP)。n 由于IP 提供非連接型傳遞服務,因此TCP應為應用程序存取網(wǎng)絡創(chuàng)造了條件,使用可靠的面向連接的傳輸層服務。該協(xié)議為建立網(wǎng)際上用戶進程之間的對話負責。此外,還確保兩個以上進程之間的可靠通信。它所提供的功能如下。n 1監(jiān)聽輸入對話建立請求。n 2請求另一網(wǎng)絡站點對話。n 3可靠的發(fā)送和接收數(shù)據(jù)。n 4適度
4、的關閉對話。應用程序部分n 用戶數(shù)據(jù)報文協(xié)議(UDP)。UDP 提供不可靠的非連接型傳輸層服務,它允許在源和目的地站點之間傳送數(shù)據(jù),而不必在傳送數(shù)據(jù)之前建立對話。此外,該協(xié)議還不使用TCP使用的端對端差錯校驗。當使用UDP時,傳輸層功能全都發(fā)揮,而開銷卻比較低。它主要用于那些不要求TCP協(xié)議的非連接型的應用程序。例如,名字服務、網(wǎng)絡管理、視頻點播和網(wǎng)絡會議等。n最后是應用程序部分。這部分包括Telnet,文件傳送協(xié)議(FTP 和TFTP),簡單的文件傳送協(xié)議(SMTP)和域名服務(DNS)等協(xié)議。nTCP/IP 使用了主干網(wǎng)絡,能連接各種主機和LAN 的多級分層結構,局部用戶能方便的聯(lián)網(wǎng),不致
5、影響到整個網(wǎng)絡系統(tǒng)。此外這種結構還有利于局部用戶控制操作和管理。nTCP/IP 具有兩個主要功能。第一是IP在網(wǎng)絡之間(有時在個別網(wǎng)絡內部)提供路由選擇。第二是TCP將TP傳遞的數(shù)據(jù)傳送的接收主機那的適當?shù)奶幚聿考nternet 協(xié)議(IP)nIP主要有以下四個主要功能:n (1)數(shù)據(jù)傳送n (2)尋址n (3)路由選擇n (4)數(shù)據(jù)報文的分段IP功能n IP的主要目的是為數(shù)據(jù)輸入/輸出網(wǎng)絡提供基本算法,為高層協(xié)議提供無連接的傳送服務。這意味著在IP將數(shù)據(jù)遞交給接收站點以前不在傳輸站點和接收站點之間建立對話(虛擬鏈路)。它只是封裝和傳遞數(shù)據(jù),但不向發(fā)送者或接收者報告包的狀態(tài),不處理所遇到的
6、故障。n IP協(xié)議不注意包內的數(shù)據(jù)類型,它所知道的一切是必須將某些稱為IP 幀頭的控制協(xié)議加到高層協(xié)議(TCP 或者UDP)所接受的數(shù)據(jù)上。IP 地址nIP地址為32位地址,一般以4個字節(jié)表示。每個字節(jié)的數(shù)字又用十進制表示,即每個字節(jié)的數(shù)的范圍是0255,且每個數(shù)字之間用點隔開,例如:12,這種記錄方法稱為“點-分”十進制記號法。IP地址的結構如下所示:網(wǎng)絡類型網(wǎng)絡ID主機IDIP地址的分類nInternet地址可分成5類:n A、B、C三類由InterNIC(Internet網(wǎng)絡信息中心)在全球范圍內統(tǒng)一分配,D、E類為特殊地址。 0 1 7 8 310網(wǎng)絡地址ID主機
7、地址IDA類IP地址10網(wǎng)絡地址ID主機地址ID0 1 2 15 16 31B類IP地址110網(wǎng)絡地址ID主機地址ID012 3 23 24 31C類IP地址1110廣播地址ID0 1 2 3 4 31D類IP地址11110保留用于將來和試驗使用 0 1 2 3 4 5 31E類IP地址IP地址說明nA 類網(wǎng)絡地址有128 個(支持127)個網(wǎng)絡,占有最左邊的一個字節(jié)(8 位)。高位(0)表示識別這種地址的類型。nB 類地址使用左邊兩個8 位用來網(wǎng)絡尋址。兩個高位(10)用于識別這種地址的類型,其余的14 位用作網(wǎng)絡地址,右邊的兩個字節(jié)(16 位)用作網(wǎng)絡節(jié)點。nC 類地址是最常見的Inter
8、net 地址。三個高位(110)用于地址類型識別,左邊三個字節(jié)的其余21 位用于尋址。C 類地址支持1046個網(wǎng)絡,每個網(wǎng)絡可多達256 端點。nD 類地址是相當新的。它的識別頭是1110,用于組播,例如用于路由器修改。nE 類地址為時延保留,其識別頭是11110。傳輸控制協(xié)議(TCP)nTCP(傳輸控制協(xié)議Transmission Control Protocol)是重要的傳輸層協(xié)議,傳輸層軟件TCP的目的是允許數(shù)據(jù)同網(wǎng)絡上的另外站點進行可靠的交換。它能提供端口編號的譯碼,以識別主機的應用程序,而且完成數(shù)據(jù)的可靠傳輸。nTCP 協(xié)議具有嚴格的內裝差錯檢驗算法確保數(shù)據(jù)的完整性。nTCP 是面向
9、字節(jié)的順序協(xié)議,這意味著包內的每個字節(jié)被分配一個順序編號,并分配給每包一個順序編號。TCP 頭信息用戶數(shù)據(jù)報文協(xié)議nUDP(用戶數(shù)據(jù)報協(xié)議User Datagram Protocol)也是TCP/IP 的傳輸層協(xié)議,它是無連接的,不可靠的傳輸服務。當接收數(shù)據(jù)時它不向發(fā)送方提供確認信息,它不提供輸入包的順序,如果出現(xiàn)丟失包或重份包的情況,也不會向發(fā)送方發(fā)出差錯報文。nUDP 的主要作用是分配和管理端口編號,以正確無誤的識別運行在網(wǎng)絡站點上的個別應用程序。由于它執(zhí)行功能時具有較低的開銷,因而執(zhí)行速度比TCP快。它多半用于不需要可靠傳輸?shù)膽贸绦颍缇W(wǎng)絡視頻點播和視頻會議等。UDP 頭信息TCP/
10、IP 協(xié)議分組服務1. 控制數(shù)據(jù)的協(xié)議n TCP以連接為基礎,即兩臺電腦必須先建立一個連接,然后才能傳輸數(shù)據(jù)。事實上,發(fā)送和接受的電腦必須一直互相通訊和聯(lián)系。n UDP是一個無連接服務,數(shù)據(jù)可以直接發(fā)送而不必在兩臺電腦之間建立一個網(wǎng)絡連接。它和有連接的TCP相比,占用帶寬少,但是無法確認數(shù)據(jù)是否真正到達了客戶端,而客戶端收到的數(shù)據(jù)也不知道是否還是原來的發(fā)送順序。2. 數(shù)據(jù)路由協(xié)議n 路由協(xié)議分析數(shù)據(jù)包的地址并且決定傳輸數(shù)據(jù)到目的電腦最佳路線。他們也可以把大的數(shù)據(jù)分成幾部分,并且在目的地再把他們組合起來。IP處理實際上傳輸數(shù)據(jù)。n ICMP(網(wǎng)絡控制信息協(xié)議Internet Control Me
11、ssage Protocol)處理IP的狀態(tài)信息,比如能影響路由決策的數(shù)據(jù)錯誤或改變。n RIP(路由信息協(xié)議Routing Information Protocol)它是幾個決定信息傳輸?shù)淖罴崖酚陕肪€協(xié)議中的一個。n OSPF(Open Shortest Path First)一個用來決定路由的協(xié)議。n ARP(地址解析協(xié)議Address Resolution Protocol)確定網(wǎng)絡上一臺電腦的數(shù)字地址。n DNS(域名系統(tǒng)Domain Name System)從機器的名字確定一個機器的數(shù)字地址。n RARP(反向地址解析協(xié)議Reverse Address Resolution Prot
12、ocol)確定網(wǎng)絡上一臺計算機的地址,和ARP正好相反。3. 用戶服務n BOOTP(啟動協(xié)議Boot Protocol) 由網(wǎng)絡服務器上取得啟動信息,然后將本地的網(wǎng)絡計算機啟動。n FTP(文件傳輸協(xié)議File Transfer Protocol)通過國際互連網(wǎng)從一臺計算機上傳輸一個或多個文件到另外一臺計算機。n TELNET(遠程登陸)允許一個遠程登陸,使用者可以從網(wǎng)絡上的一臺機器通過TELNET連線到另一臺機器,就像使用者直接在本地操作一樣。n EGP(外部網(wǎng)關協(xié)議Exterior Gateway Protocol)為外部網(wǎng)絡傳輸路由信息。n GGP(網(wǎng)關到網(wǎng)關協(xié)議Gateway-to-
13、Gateway Protocol)在網(wǎng)關和網(wǎng)關之間傳輸路由協(xié)議。n IGP(內部網(wǎng)關協(xié)議Interior Gateway Protocol)在內部網(wǎng)絡傳輸路由信息。4. 其他協(xié)議(也為網(wǎng)絡提供了重要的服務)n NFS(網(wǎng)絡文件系統(tǒng)Network File System)允許將一臺機器的目錄被另一臺機器上的用戶安裝(Mount)到自己的機器上,就像是對本地文件系統(tǒng)進行操作一樣進行各式各樣的操作。n NIS(網(wǎng)絡信息服務Network Information Service)對整個網(wǎng)絡用戶的用戶名、密碼進行統(tǒng)一管理,簡化在NIS 服務下整個網(wǎng)絡登陸的用戶名密碼檢查。n RPC(遠程過程調用Remo
14、te Procedure Call)通過它可以允許遠程的應用程序通過簡單的、有效的手段聯(lián)系本地的應用程序,反之也是。n SMTP(簡單郵件傳輸協(xié)議Simple Mail Transfer Protocol)一個專門為電子郵件在多臺機器中傳輸?shù)膮f(xié)議,平時發(fā)郵件的SMTP 服務器提供的必然服務。n SNMP(簡單網(wǎng)絡管理協(xié)議Simple Network Management Protocol)這是一項為超級用戶準備的服務,超級用戶可以通過它來進行簡單的網(wǎng)絡管理。端口n TCP和UDP協(xié)議是以IP協(xié)議為基礎的傳輸,為了方便多種應用程序,區(qū)分不同應用程序的數(shù)據(jù)和狀態(tài),引入了端口的概念。n 端口是一個1
15、6位的整數(shù)類型值,通常稱這個值為端口號。如果是服務程序,則需要對某個端口進行綁定,這樣某個客戶端可以方位本主機上的此端口來與應用程序進行通信。由于IP地址只能對主機進行區(qū)分,而加上端口號就可以對區(qū)分此主機上的應用程序。實際上,IP地址和端口號的組合,可以確定在網(wǎng)絡上的一個程序通路,端口號實際上是操作系統(tǒng)標識應用程序的一種方法。主機字節(jié)序和網(wǎng)絡字節(jié)序n在使用網(wǎng)絡進行程序設計中會碰到的一個問題是字節(jié)序的問題,這在基于單機或者同類型機器進行開發(fā)的過程中很少遇到。由于網(wǎng)絡的特點是將Internet上不同的網(wǎng)絡設備和主機進行連接和通信,這決定了使用網(wǎng)絡進行開發(fā)的程序的特點就是要兼容各種類型的設備,其中的
16、數(shù)據(jù)在不同的設備上要有唯一的含義。字節(jié)序的問題是上述情況下的典型問題。字節(jié)序的含義n 字節(jié)序的問題是由于CPU對整數(shù)在內存中的存放方式造成的。字節(jié)多于一個字節(jié)的數(shù)據(jù)類型在內存中的存放順序叫主機字節(jié)序。最常見的字節(jié)序有兩種,小端字節(jié)序和大端字節(jié)序:n 小端字節(jié)序,即Little Endian(簡稱LE),將數(shù)據(jù)的最低字節(jié)放在內存的起始位置。小端字節(jié)序的特點是內存地址較低的位存放數(shù)據(jù)的低位,內存地址高的位存放數(shù)據(jù)的高位,與思維的習慣。采用低字節(jié)序的CPU有x86架構的intel系列產(chǎn)品。n 大端字節(jié)序,即Big Endian(簡稱BE),將數(shù)據(jù)的高字節(jié)放在內存的起始位置。大端字節(jié)序的特點是內存中低
17、字節(jié)位置存放數(shù)據(jù)的高位字節(jié),內存中的高位字節(jié)存放數(shù)據(jù)的較低字節(jié)數(shù)據(jù),與思維習慣不一致,但是與實際數(shù)據(jù)的表達方式是一致的。采用大端字節(jié)序的CPU有PowerPC的UNIX系統(tǒng)。網(wǎng)絡字節(jié)序的轉換n 網(wǎng)絡的字節(jié)序標準規(guī)定為大端字節(jié)序,不同平臺上會對主機字節(jié)序進行轉化,成為網(wǎng)絡字節(jié)序后再進行傳送,到主機后再轉化為主機字節(jié)序,數(shù)據(jù)的傳輸就不會產(chǎn)生傳輸造成的問題了。同一個數(shù)據(jù)在不同的平臺上可以使用網(wǎng)絡字節(jié)序的轉換函數(shù)來實現(xiàn)。什么是套接字(SOCKET)n套接口是對網(wǎng)絡中不同主機上應用進程之間進行雙向通信的端點的抽象,一個套接口就是網(wǎng)絡上進程通信的一端,提供了應用層進程利用網(wǎng)絡協(xié)議棧交換數(shù)據(jù)的機制。Sock
18、et 的功能n Socket 的英文原意就是“孔”或“插座”,將電話系統(tǒng)與面向連接的Socket 機制相比,有著驚人相似的地方。以一個國家級的電話網(wǎng)為例。n 電話的通話雙方相當于相互通信的兩個進程;通話雙方所在的地區(qū)(享有一個全局唯一的區(qū)號)相當于一個網(wǎng)絡,區(qū)號是它的網(wǎng)絡地址;區(qū)內的一個單位的交換機相當于一臺主機,主機分配給每個用戶的局內號碼相當于Socket 號.n 任何用戶在通話之前,首先要占有一部電話機,相當于申請一個Socket 號;同時要知道對方的電話號碼,相當于對方有一個Socket。n 然后向對方撥號呼叫,相當于發(fā)出連接請求(假如對方不在同一區(qū)內,還要撥對方區(qū)號,相當于給出網(wǎng)絡地
19、址)。對方假如在場并空閑(相當于通信的另一主機開機且可以接受連接請求),拿起電話話筒,雙方就可以正式通話,相當于連接成功。n 雙方通話的過程,是向電話機發(fā)出信號和從電話機接受信號的過程,相當于向Socket 發(fā)送數(shù)據(jù)和從Socket 接受數(shù)據(jù)。通話結束后,一方掛起電話機,相當于關閉Socket,撤消連接。套接字基礎n從套接字所處的地位來講,套接字上聯(lián)應用進程,下聯(lián)網(wǎng)絡協(xié)議棧,是應用程序通過網(wǎng)絡協(xié)議棧進行通信的接口,是應用程序與網(wǎng)絡協(xié)議棧進行交互的接口。 套接字基礎(續(xù))n從實現(xiàn)的角度來講,非常復雜。套接字是一個復雜的軟件機構,包含了一定的數(shù)據(jù)結構,包含許多選項,由操作系統(tǒng)內核管理。n從使用的角
20、度來講,非常簡單。對于套接字的操作形成了一種網(wǎng)絡應用程序的編程接口(API)。n操作套接字的編程接口函數(shù)稱作套接字編程接口,套接字是它的操作對象。n總之,套接字是網(wǎng)絡通信的基石。常用的socketn流式套接字:它提供基于TCP協(xié)議的雙向、可靠、有序且不重復的無記錄邊界的數(shù)據(jù)流。n數(shù)據(jù)報套接字:它提供基于UDP協(xié)議的雙向數(shù)據(jù)流,但不一定可靠、有序和不重復。n原始套接字:它提供網(wǎng)絡下層通信協(xié)議的直接訪問。一般用于開發(fā)新的網(wǎng)絡層協(xié)議,如新的IP協(xié)議等。UDPTCP三種表示套接字地址的結構n(1)struct sockaddr這個結構用來存儲套接字地址。數(shù)據(jù)定義:struct sockaddr uns
21、igned short sa_family; /* address族, AF_xxx */char sa_data14; /* 14 bytes的協(xié)議地址*/;sa_family 一般來說,都是“AF_INET”。sa_data 包含了一些遠程電腦的地址、端口和套接字的數(shù)目,它里面的數(shù)據(jù)是雜溶在一切的。三種表示套接字地址的結構(續(xù))n(2). struct sockaddr_in為了處理struct sockaddr, 程序員建立了另外一個相似的結構struct sockaddr_in:struct sockaddr_in (“in” 代表“Internet”)struct sockaddr_
22、in short int sin_family; /* Internet地址族*/unsigned short int sin_port; /* 端口號*/struct in_addr sin_addr; /* Internet地址*/unsigned char sin_zero8; /* 添0(和struct sockaddr一樣大?。?/;這個結構提供了方便的手段來訪問socket address(struct sockaddr)結構中的每一個元素。三種表示套接字地址的結構(續(xù))n(3)struct in_addr專門用來存儲 IP地址,其定義如下:/* 因特網(wǎng)地址(a structure
23、 for historical reasons) */struct in_addr unsigned long s_addr;如果你聲明了一個“ ina ” 作為一個struct sockaddr_in 的結構, 那么“ina.sin_addr.s_addr”就是4 個字節(jié)的IP 地址(按網(wǎng)絡字節(jié)順序排放)。需要注意的是,即使你的系統(tǒng)仍然使用聯(lián)合而不是結構來表示struct in_addr,你仍然可以用上面的方法得到4 個字節(jié)的IP 地址.三種表示套接字地址的結構(續(xù))n(4).這些數(shù)據(jù)結構的一般用法:首先,定義一個Sockaddr_in的結構實例,并將它清零。比如:struct sockad
24、dr_in myad;memset(&myad,0,sizeof(struct sockaddr_in);然后,為這個結構賦值,比如:myad.sin_family=AF_INET;myad.sin_port=htons(8080); myad.sin_addr.s_addr=htonl(INADDR-ANY);第三步:在函數(shù)調用中使用時,將這個結構強制轉換為sockaddr類型。如:accept(listenfd,(sockaddr*)(&myad),&addrlen);本機字節(jié)順序和網(wǎng)絡字節(jié)順序n 在具體計算機中的多字節(jié)數(shù)據(jù)的存儲順序,稱為本機字節(jié)順序。多字節(jié)數(shù)據(jù)在網(wǎng)絡協(xié)議報頭中的存儲順序
25、,稱為網(wǎng)絡字節(jié)順序。n 在網(wǎng)絡上面有著許多類型的機器,這些機器在表示數(shù)據(jù)的字節(jié)順序是不同的, 比如i386芯片是低字節(jié)在內存地址的低端,高字節(jié)在高端,而alpha芯片卻相反. n 為了統(tǒng)一起來,在Linux下面,有專門的字節(jié)轉換函數(shù). unsigned long int htonl(unsigned long int hostlong) unsigned short int htons(unisgned short int hostshort) unsigned long int ntohl(unsigned long int netlong) unsigned short int ntohs
26、(unsigned short int netshort) n 在這四個轉換函數(shù)中,h 代表host, n 代表 network.s 代表short l 代表long 第一個函數(shù)的意義是將本機器上的long數(shù)據(jù)轉化為網(wǎng)絡上的long. 其他幾個函數(shù)的意義也差不多. 點分十進制的IP地址的轉換n(1) inet_aton將strptr所指的字符串轉換成32位的網(wǎng)絡字節(jié)序二進制值。 include int inet_aton(const char *strptr,struct in_addr *addrptr);n(2) inet_addr功能同上,返回地址。int_addr_t inet_add
27、r(const char *strptr);n(3) inet_ntoa將32位網(wǎng)絡字節(jié)序二進制地址轉換成點分十進制的串。 char *inet_ntoa(stuct in_addr inaddr);域名服務在網(wǎng)絡上標志一臺機器可以用IP或者是用域名.那么我們怎么去進行轉換呢?structhostent*gethostbyname(constchar*hostname) 可以將機器名(如 )轉換為一個結構指針.在這個結構里面儲存了域名的信息 structhostent*gethostbyaddr(constchar*addr,intlen,inttype) 可以將一個32位的IP地址(C0A8
28、0001)轉換為結構指針. 這兩個函數(shù)失敗時返回NULL 且設置h_errno錯誤變量,調用h_strerror()可以得到詳細的出錯信息 struct hostent的定義: struct hostent char *h_name; /* 主機的正式名稱 */ char *h_aliases; /* 主機的別名 */ int h_addrtype; /* 主機的地址類型 AF_INET*/ int h_length; /* 主機的地址長度 對于IP4 是4字節(jié)32位*/ char *h_addr_list; /* 主機的IP地址列表 */ #define h_addr h_addr_list
29、0 /* 主機的第一個IP地址*/套接字的工作過程初等網(wǎng)絡函數(shù)n 1 socket #include int socket(int domain, int type,int protocol) socket為網(wǎng)絡通訊做基本的準備.成功時返回文件描述符,失敗時返回-1。通過errno可知道出錯的詳細情況. n 參數(shù)說明:domain:說明我們網(wǎng)絡程序所在的主機采用的通訊協(xié)族(AF_UNIX和AF_INET等)。AF_UNIX只能夠用于單一的Unix系統(tǒng)進程間通信,而AF_INET是針對Internet的,因而可以允許在遠程主機之間通信當我們 man socket時發(fā)現(xiàn) domain可選項是 PF
30、_*而不是AF_*,因為glibc是posix的實現(xiàn) 所以用PF代替了AF,不過我們都可以使用的. type:我們網(wǎng)絡程序所采用的通訊協(xié)議。SOCK_STREAM表明我們用的是TCP協(xié)議,這樣會提供按順序的,可靠,雙向,面向連接的比特流. SOCK_DGRAM 表明我們用的是UDP協(xié)議,這樣只會提供定長的,不可靠,無連接的通信。 SOCK_RAW 原始套接字,用來直接訪問IP協(xié)議。protocol:由于我們指定了type,所以這個地方我們一般只要用0來代替就可以了。初等網(wǎng)絡函數(shù)(續(xù))n2 bind int bind(int sockfd, struct sockaddr *my_addr, i
31、nt addrlen) bind將本地的端口同socket返回的文件描述符捆綁在一起.成功是返回0,失敗的情況和socket一樣。n參數(shù)說明sockfd:是由socket調用返回的文件描述符. addrlen:是sockaddr結構的長度. my_addr:是一個指向sockaddr的指針. 構造套接字地址舉例int listenfd;struct sockaddr_in server_addr;listenfd=socket(AF_INET,SOCK_STREAM,0);bzero(&server_addr,sizeof(server_addr); server_addr.sin_famil
32、y=AF_INET;server_addr.sin_port=htons(80);inet_pton(AF_INET, “44”, & server_addr.sin_addr);bind(listenfd,& server_addr,sizeof(struct sockaddr_in) 初等網(wǎng)絡函數(shù)(續(xù))n3 listen int listen(int sockfd,int backlog) listen函數(shù)將bind的文件描述符變?yōu)楸O(jiān)聽套接字。返回的情況和bind一樣。n參數(shù)說明sockfd:是bind后的文件描述符.。backlog:設置請求排隊的最大長度.當有多
33、個客戶端程序和服務端相連時, 使用這個表示可以介紹的排隊長度。初等網(wǎng)絡函數(shù)(續(xù))n4 accept int accept(int sockfd, struct sockaddr *addr,int *addrlen)accept成功時返回最后的服務器端的文件描述符,這個時候服務器端可以向該描述符寫信息了。失敗時返回-1 。n參數(shù)說明sockfd:是listen后的文件描述符.。addr,addrlen是用來給客戶端的程序填寫的,服務器端只要傳遞指針就可以了.。bind,listen和accept是服務器端用的函數(shù),accept調用時,服務器端的程序會一直阻塞到有一個 客戶程序發(fā)出了連接, ac
34、cept成功時返回最后的服務器端的文件描述符。初等網(wǎng)絡函數(shù)(續(xù))n5 connect int connect(int sockfd, struct sockaddr * serv_addr,int addrlen) connect函數(shù)是客戶端用來同服務端連接的。成功時返回0,sockfd是同服務端通訊的文件描述符 。失敗時返回-1。n參數(shù)說明sockfd:socket返回的文件描述符. serv_addr:儲存了服務器端的連接信息.其中sin_add是服務端的地址 addrlen:serv_addr的長度 完整的讀寫函數(shù)n 一旦我們建立了連接,我們的下一步就是進行通信了.n 在Linux下面把
35、我們前面建立的通道 看成是文件描述符,這樣服務器端和客戶端進行通信時候,只要往文件描述符里面讀寫東西了. 就象我們往文件讀寫一樣。n 1 寫函數(shù)write ssize_t write(int fd,const void *buf,size_t nbytes) write函數(shù)將buf中的nbytes字節(jié)內容寫入文件描述符fd.成功時返回寫的字節(jié)數(shù).失敗時返回-1. 并設置errno變量. 在網(wǎng)絡程序中,當我們向套接字文件描述符寫時有倆種可能. 1)write的返回值大于0,表示寫了部分或者是全部的數(shù)據(jù). 2)返回的值小于0,此時出現(xiàn)了錯誤.我們要根據(jù)錯誤類型來處理. 如果錯誤為EINTR表示在寫
36、的時候出現(xiàn)了中斷錯誤. 如果為EPIPE表示網(wǎng)絡連接出現(xiàn)了問題(對方已經(jīng)關閉了連接). 寫實例int my_write(int fd,void *buffer,int length) int bytes_left; int written_bytes; char *ptr; ptr=buffer; bytes_left=length; while(bytes_left0) /* 開始寫*/ written_bytes=write(fd,ptr,bytes_left); if(written_bytes0) bytes_read=read(fd,ptr,bytes_read); if(bytes
37、_read0) 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ù))n 3 數(shù)據(jù)的傳遞 有了上面的兩個函數(shù),我們就可以向客戶端或者是服務端傳遞數(shù)據(jù)了.比如我們要傳遞一個結構.可以使用如下方式 :/* 客戶端向服務端寫 */ struct my_struct my_struct_client; write(fd,(void *)&my_stru
38、ct_client,sizeof(struct my_struct); /* 服務端的讀*/ char buffersizeof(struct my_struct); struct *my_struct_server; read(fd,(void *)buffer,sizeof(struct my_struct); my_struct_server=(struct my_struct *)buffer; 在網(wǎng)絡上傳遞數(shù)據(jù)時我們一般都是把數(shù)據(jù)轉化為char類型的數(shù)據(jù)傳遞.接收的時候也是一樣的。注意的是我們沒有必要在網(wǎng)絡上傳遞指針(因為傳遞指針是沒有任何意義的,我們必須傳遞指針所指向的內容) 。面
39、向連接的傳輸層套接字舉例n 服務器端程序/* 服務器程序 (server.c) */ #include #include #include #include #include #include #include #include int main(int argc, char *argv) int sockfd,new_fd; struct sockaddr_in server_addr; struct sockaddr_in client_addr; int sin_size,portnumber; char hello=Hello! Are You Fine?n; if(argc!=2)
40、fprintf(stderr,Usage:%s portnumberan,argv0); exit(1); if(portnumber=atoi(argv1)0) fprintf(stderr,Usage:%s portnumberan,argv0); exit(1); /* 服務器端開始建立socket描述符 */ if(sockfd=socket(AF_INET,SOCK_STREAM,0)=-1) fprintf(stderr,Socket error:%sna,strerror(errno); exit(1); /* 服務器端填充 sockaddr結構 */ bzero(&server
41、_addr,sizeof(struct sockaddr_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,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr)=-1) fprintf(stderr,Bind error:%sna,strerror(errno); exit(
42、1); /* 監(jiān)聽sockfd描述符 */ if(listen(sockfd,5)=-1) fprintf(stderr,Listen error:%sna,strerror(errno); exit(1); while(1) /* 服務器阻塞,直到客戶程序建立連接 */ sin_size=sizeof(struct sockaddr_in); if(new_fd=accept(sockfd,(struct sockaddr *)(&client_addr),&sin_size)=-1) fprintf(stderr,Accept error:%sna,strerror(errno); exi
43、t(1); fprintf(stderr,“Server get connection from %sn”, inet_ntoa(client_addr.sin_addr); if(write(new_fd,hello,strlen(hello)=-1) fprintf(stderr,“Write Error:%sn”,strerror(errno); exit(1); /* 這個通訊已經(jīng)結束 */ close(new_fd); /* 循環(huán)下一個 */ close(sockfd); exit(0); 面向連接的傳輸層套接字舉例n 客戶端程序/* 客戶端程序 client.c */ #inclu
44、de #include #include #include #include #include #include #include int main(int argc, char *argv) int sockfd; char buffer1024; struct sockaddr_in server_addr; struct hostent *host; int portnumber,nbytes; if(argc!=3) fprintf(stderr,Usage:%s hostname portnumberan,argv0); exit(1); if(host=gethostbyname(
45、argv1)=NULL) fprintf(stderr,Gethostname errorn); exit(1); if(portnumber=atoi(argv2)h_addr); /* 客戶程序發(fā)起連接請求 */ if(connect(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr)=-1) fprintf(stderr,Connect Error:%san,strerror(errno); exit(1); /* 連接成功了 */ if(nbytes=read(sockfd,buffer,1024)=-1)
46、fprintf(stderr,Read Error:%sn,strerror(errno); exit(1); buffernbytes=0; printf(I have received:%sn,buffer); /* 結束通訊 */ close(sockfd); exit(0); 無連接的套接字編程使用數(shù)據(jù)報套接字開發(fā)網(wǎng)絡應用程序,既可以采用客戶/服務器模式,也可以采用對等模式。客戶/服務器模式UDP通信機制n在服務器端服務器先使用AF_INET協(xié)議族創(chuàng)建UDP數(shù)據(jù)報類型的套接字,該socket類型為SOCK_DGRAM;然后服務器調用bind函數(shù),給此UDP套接字綁定一個端口;調用rec
47、vfrom函數(shù)在指定的端口上等待客戶端發(fā)送來的UDP數(shù)據(jù)報。n在客戶端先通過socket函數(shù)創(chuàng)建一個數(shù)據(jù)報套接字;然后由操作系統(tǒng)為這個套接字分配端口號;此后客戶端就可以使用sendto函數(shù)向一個指定的地址發(fā)送一個UDP套接字。在服務器端收到套接字后,從recvfrom中返回,在對數(shù)據(jù)進行處理之后,再用sendto函數(shù)處理的結果返回客戶端。UDP與TCP的比較nUDP服務器通常是非連接的因而UDP服務器進程不需要象TCP服務器那樣在傾聽套接字上接收新建的連接;UDP只需要在綁定的端口上等待客戶機發(fā)送來的UDP數(shù)據(jù)報,并對其進行處理和響應。一個TCP服務器進程只有在完成了對某客戶機的服務后,才能為
48、其他的客戶機提供服務;UDP客戶機并不獨占服務器,UDP服務器只是接收數(shù)據(jù)報,處理并返回結果。UDP的應用場合nUDP支持廣播和多播。如果要使用廣播和多播,必須使用UDP套接字。nUDP套接字沒有連接的建立和終止過程。UDP只需要兩個分組來交換一個請求和應答。nUDP不適合海量數(shù)據(jù)的傳輸。無連接的傳輸層套接字 n兩個常用的函數(shù) # include int recvfrom(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr * from int *fromlen) int sendto(int sockfd,const
49、 void *msg,int len,unsigned int flags,struct sockaddr *to int tolen) sockfd,buf,len的意義和read,write一樣,分別表示套接字描述符,發(fā)送或接收的緩沖區(qū)及大小recvfrom負責從sockfd接收數(shù)據(jù),如果from不是NULL,那么在from里面存儲了信息來源的情況,如果對信息的來源不感興趣,可以將from和fromlen設置為NULL.sendto負責向to發(fā)送信息.此時在to里面存儲了收信息方的詳細資料.UDP實例n一個實例程序編譯好后,運行時需指定雙方所使用的IP地址和端口號,第一個參數(shù)是對方的IP地
50、址,然后是對方的端口號,之后是本端的IP地址和端口號。例如在test1的終端輸入:a.out 00 4321 68 5678同時在test2上輸入: a.out 68 5678 00 4321然后雙方都可以發(fā)送信息給對方了/*first step in udp programming*/#include #include #include #include #define BUFLEN 255int main(int argc,char *argv)struct sockaddr_in peeraddr,l
51、ocaladdr;int sockfd;char recmsgBUFLEN+1;int socklen,n;if(argc!=5)printf(%s n,argv0);exit(0);sockfd=socket(AF_INET,SOCK_DGRAM,0);if(sockfd0)fprintf(stderr,socket creating error in udptalk.c!n);exit(1);socklen=sizeof(struct sockaddr_in);memset(&peeraddr,0,socklen);peeraddr.sin_family=AF_INET;peeraddr.
52、sin_port=htons(atoi(argv2);if(inet_pton(AF_INET,argv1,&peeraddr.sin_addr)=0)printf(Wrong dest IP address!n); exit(0);memset(&localaddr,0,socklen);localaddr.sin_family=AF_INET;localaddr.sin_port=htons(atoi(argv4);if(inet_pton(AF_INET,argv3,&localaddr.sin_addr)=0)printf(Wrong source IP address!n);exit
53、(0);if(bind(sockfd,&localaddr,socklen)0)fprintf(stderr,bind local address error in udptalk.c!n);exit(2);if(fgets(recmsg,BUFLEN,stdin)=NULL) exit(0);if(sendto(sockfd,recmsg,strlen(recmsg),0,&peeraddr,socklen)0)fprintf(stderr,sendto error in udptalk.c!n);perror();exit(3);for(;)n=recvfrom(sockfd,recmsg
54、,BUFLEN,0,&peeraddr,&socklen);if(n0)fprintf(stderr,recvfrom error in );perror();exit(4);elserecmsgn=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,sendto error in udptalk.c!n);perror();exit(3); 對第一個UDP
55、例程的思考n思考:1. 只有來自對方IP和端口號的數(shù)據(jù)報才予以處理,如何過濾掉其它數(shù)據(jù)報?2. 雙方發(fā)送和接收交替進行,只要有一方發(fā)出數(shù)據(jù)報,對方阻塞的狀態(tài)就能消除。如果一個數(shù)據(jù)報丟失,通信雙方都在recvfrom中阻塞,永遠等待。超時機制的設置?對第一個UDP例程的思考n解決第一個問題:接收數(shù)據(jù)后,加入對數(shù)據(jù)報地址的檢驗:if(memcmp(recvaddr,perraddr,socklen)!=0) continue;這樣就將來自其他地址的數(shù)據(jù)報拒之門外了。對第一個UDP例程的思考n 解決第二個問題:前面提到的sock選項SO_RCVTIMEO就可以完成阻塞超時的設置。在程序中加入:# i
56、nclude Struct timeval recto;Int tolen=sizeof(struct timeval);/*建立socket等操作/rcvto.tv_sec=3; /*這兩句對rcvto定時為3秒0毫秒*/rccvto.tv_usec=0;Setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,&rcvto,tolen);getsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,&rcvto,&tolen);Printf(“receive timeout setted is %ld second %ld millisecond
57、n”,rcvto.tv_sec,rcvto.tv_usec);n 如果顯示Receive timeout setted is 3 second 0 millisecond,那么就設置成功了;n 如果結果是Receive timeout setted is 0 second 0 millisecond,就意味著超時時間為無窮大。n 設置了SO_RCVTIMEO,那么在發(fā)生超時后,recvfrom將返回,返回值為-1,同時errno被置為EWOULDBLOCK。高級套接字函數(shù)n1、recv和send recv和send函數(shù)提供了和read和write差不多的功能。不過它們提供了第四個參數(shù)來控制讀寫
58、操作。 int recv(int sockfd,void *buf,int len,int flags) int send(int sockfd,void *buf,int len,int flags) 前面的三個參數(shù)和read,write一樣,第四個參數(shù)可以是0或者是以下的組合:MSG_DONTROUTE MSG_DONTROUTE 不查找路由表不查找路由表 MSG_OOB MSG_OOB 接受或者發(fā)送帶外數(shù)據(jù)接受或者發(fā)送帶外數(shù)據(jù) MSG_PEEK MSG_PEEK 查看數(shù)據(jù)查看數(shù)據(jù), ,并不從系統(tǒng)緩沖區(qū)移走數(shù)據(jù)并不從系統(tǒng)緩沖區(qū)移走數(shù)據(jù) MSG_WAITALL MSG_WAITALL 等待所
59、有數(shù)據(jù)等待所有數(shù)據(jù) n MSG_DONTROUTE:是send函數(shù)使用的標志。這個標志告訴IP協(xié)議,目的主機在本地網(wǎng)絡上面,沒有必要查找路由表。這個標志一般用網(wǎng)絡診斷和路由程序里面。n MSG_OOB:表示可以接收和發(fā)送帶外的數(shù)據(jù)。關于帶外數(shù)據(jù)我們以后會解釋的。n MSG_PEEK:是recv函數(shù)的使用標志。表示只是從系統(tǒng)緩沖區(qū)中讀取內容,而不清楚系統(tǒng)緩沖區(qū)的內容。這樣下次讀的時候,仍然是一樣的內容。一般在有多個進程讀寫數(shù)據(jù)時可以使用這個標志。n MSG_WAITALL:是recv函數(shù)的使用標志。表示等到所有的信息到達時才返回。使用這個標志的時候recv回一直阻塞,直到指定的條件滿足,或者是發(fā)
60、生了錯誤。1) 當讀到了指定的字節(jié)時,函數(shù)正常返回.返回值等于len。 2) 當讀到了文件的結尾時,函數(shù)正常返回,返回值小于len 。3)當操作發(fā)生錯誤時,返回-1,且設置錯誤為相應的錯誤號(errno)。n 如果flags為0,則和read,write一樣的操作。高級套接字函數(shù)(續(xù))n recvmsg和sendmsg recvmsg和sendmsg可以實現(xiàn)前面所有的讀寫函數(shù)的功能。int recvmsg(int sockfd,struct msghdr *msg,int flags) int sendmsg(int sockfd,struct msghdr *msg,int flags) n
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 獨立董事2025年度履職評價與激勵措施合同3篇
- 二零二五年度禾青幼兒園教玩具采購與幼兒園設施維護合同3篇
- 二零二五搬家公司合同模板:搬家保險責任與賠償條款2篇
- 二零二五版物流行業(yè)預付款擔保合同2篇
- 二零二五版搬家服務與家政服務融合合同樣本2篇
- 二零二五年度蔬菜電子商務合同:線上銷售平臺與賣家之間的規(guī)則2篇
- 二零二五版汽車零部件購銷合同標準及售后服務模板3篇
- 二零二五年度國際教育機構合作辦學合同3篇
- 二零二五年度高壓變壓器安裝及安全防護技術合同3篇
- 二零二五版社保繳納與工傷保險待遇保障合同3篇
- ICU常見藥物課件
- CNAS實驗室評審不符合項整改報告
- 農民工考勤表(模板)
- 承臺混凝土施工技術交底
- 臥床患者更換床單-軸線翻身
- 計量基礎知識培訓教材201309
- 中考英語 短文填詞、選詞填空練習
- 一汽集團及各合資公司組織架構
- 阿特拉斯基本擰緊技術ppt課件
- 初一至初三數(shù)學全部知識點
- 新課程理念下的班主任工作藝術
評論
0/150
提交評論