第 12 章 網(wǎng)絡(luò)編程_第1頁
第 12 章 網(wǎng)絡(luò)編程_第2頁
第 12 章 網(wǎng)絡(luò)編程_第3頁
第 12 章 網(wǎng)絡(luò)編程_第4頁
第 12 章 網(wǎng)絡(luò)編程_第5頁
已閱讀5頁,還剩60頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

第12章網(wǎng)絡(luò)編程內(nèi)容提要網(wǎng)絡(luò)編程概述互聯(lián)網(wǎng)傳輸協(xié)議

Socket上的讀寫操作

Unix域套接字套接字選項構(gòu)建并發(fā)服務(wù)器12.1網(wǎng)絡(luò)編程概述網(wǎng)絡(luò)套接字Socket

TCP/IP誕生于4.4BSD,隨著TCP/IP在互聯(lián)網(wǎng)的廣泛應(yīng)用,編程接口BSDsocket也事實上成為網(wǎng)絡(luò)接口標準。目前,已被包括Linux在內(nèi)的眾多操作系統(tǒng)支持。

BSDsocket為一種通用網(wǎng)絡(luò)編程接口,支持豐富的網(wǎng)絡(luò)協(xié)議,例如,ipx/spx等。系統(tǒng)調(diào)用接口層VFS接口層Socket抽象層EthernetTokenRingPPPSLIP網(wǎng)絡(luò)設(shè)備驅(qū)動接口層PF_INETPF_PACKETPF_IPXPF_UNIXiptcpudp設(shè)備驅(qū)動層協(xié)議層接口層SOCK_DGRAMSOCK_RAWSOCK_RAWSOCK_DGRAMSOCK_STREAMreadwriteclosesocketrecvsendLinux內(nèi)核支持的協(xié)議客戶機/服務(wù)器模型socket采用客戶機/服務(wù)器模式,服務(wù)器監(jiān)聽客戶機發(fā)送的連接請求,客戶機需預(yù)先獲知服務(wù)器的地址,雙方連接建立后,可實現(xiàn)雙向數(shù)據(jù)傳輸。

傳輸層通常提供兩種類型的傳輸服務(wù),面向連接的傳輸服務(wù)和無連接的傳輸服務(wù),對于面向連接的傳輸服務(wù),可確保雙方傳輸數(shù)據(jù)的有序和可靠。對于無連接的傳輸協(xié)議,無須建立連接,可直接根據(jù)對方地址收發(fā)數(shù)據(jù)。4TCP/IP協(xié)議TCP/IP作為互聯(lián)網(wǎng)的標準協(xié)議族,其傳輸層為上層提供TCP和UDP兩種服務(wù)。

TCP是一種面向連接的傳輸協(xié)議,通信雙方以字節(jié)流方式可靠地交換數(shù)據(jù),用戶無需關(guān)心內(nèi)部復(fù)雜的協(xié)商邏輯,但TCP也會消耗一定的帶寬資源。

UDP是一種無連接的數(shù)據(jù)報協(xié)議,以數(shù)據(jù)報為單位,數(shù)據(jù)報在傳輸過程中可能丟失和失序,UDP消耗相對較少的帶寬資源。應(yīng)用編程接口分類API功能描述socketAPIsocket創(chuàng)建套接字bind綁定地址listen監(jiān)聽綁定地址上的連接請求accept接收來自綁定地址上的連接請求connect向服務(wù)器發(fā)起連接請求recv/recvfrom/recvmsg接收數(shù)據(jù)send/sendto/sendmsg發(fā)送數(shù)據(jù)close/shutdown關(guān)閉/優(yōu)雅關(guān)閉sendfile在內(nèi)核空間傳輸文件socketpair創(chuàng)建互聯(lián)套接字getsockopt/setsockopt獲取/設(shè)置套接字選項12.2互聯(lián)網(wǎng)傳輸協(xié)議內(nèi)容提要面向連接的傳輸協(xié)議TCPsocket編程接口無連接的傳輸協(xié)議UDP面向連接的傳輸協(xié)議TCPTCP是一種面向連接基于字節(jié)流的可靠傳輸協(xié)議,確保通信雙方數(shù)據(jù)傳輸?shù)挠行蚝驼_。采用客戶機/服務(wù)器模式,服務(wù)器監(jiān)聽客戶機發(fā)起的連接請求,在雙方建立連接后,便可進行數(shù)據(jù)傳輸?;赥CP的客戶機/服務(wù)器模式服務(wù)器端請求數(shù)據(jù)socket()bind()listen()accept()socket()connect()send()recv()客戶端(Blockuntilconnection)建立連接recv()send()回復(fù)數(shù)據(jù)close()關(guān)閉連接recv()close()創(chuàng)建套接字1.socket函數(shù)頭文件

#include<sys/types.h> #include<sys/socket.h>函數(shù)原型

int

socket(intdomain,inttype,intprotocol);功能 創(chuàng)建套接字。參數(shù)

domain:協(xié)議族。

type:協(xié)議類型。

protocol:默認為0,通常用于原始套接字選項。返回值 成功:套接字的文件描述符,錯誤:返回-1。創(chuàng)建套接字(續(xù))參數(shù)domain描述AF_UNIX本地通信協(xié)議AF_INETIPv4互聯(lián)網(wǎng)協(xié)議AF_INET6IPv6互聯(lián)網(wǎng)協(xié)議AF_IPXIPXnovellprotocolsAF_NETLINK配置協(xié)議參數(shù)type描述SOCK_STREAM面向連接的字節(jié)流服務(wù)SOCK_DGRAM無連接不可靠數(shù)據(jù)報服務(wù)SOCK_RAW底層協(xié)議訪問服務(wù)socket函數(shù)中參數(shù)type的定義函數(shù)中參數(shù)domain的定義綁定地址頭文件

#include<sys/types.h> #include<sys/socket.h>函數(shù)原型

int

bind(int

sockfd,struct

sockaddr*addr,socklen_t

addrlen);功能 綁定本地地址。參數(shù)

sockfd:套接字的文件描述符。

addr:ip地址。

addrlen:地址長度。返回值 成功返回0,錯誤:返回-1。綁定地址(續(xù))sockaddr使用更一般的類型,其定義如下。

struct

sockaddr{

sa_family_t

sa_family;//協(xié)議族

charsa_data[14];//內(nèi)容與協(xié)議族有關(guān)

}TCP/IP協(xié)議族的地址類型有ipv4和ipv兩種,下面僅以ipv4未例,其地址類型sockaddr_in的定義如下。struct

sockaddr_in{shortint

sin_family;//取值為AF_INETunsignedshortint

sin_port;//端口號struct

in_addr

sin_addr;//IP地址...};監(jiān)聽套接字頭文件

#include<sys/socket.h>函數(shù)原型

int

listen(int

sockfd,intbacklog);功能 監(jiān)聽套接字上的連接請求。參數(shù)

sockfd:套接字的文件描述符。

backlog:可容納連接請求的數(shù)量。返回值 成功返回0,錯誤返回-1。接收連接頭文件

#include<sys/types.h> #include<sys/socket.h>函數(shù)原型

int

accept(int

sockfd,struct

sockaddr*addr,socklen_t*addrlen);功能 接收連接。參數(shù)

sockfd:套接字的文件描述符。

addr:連接請求的地址。

addrlen:地址長度。返回值 成功返回為新連接創(chuàng)建的套接字,失敗返回-1。發(fā)起連接請求頭文件

#include<sys/types.h> #include<sys/socket.h>函數(shù)原型

int

connect(int

sockfd,struct

sockaddr*addr,socklen_t

addrlen);功能 向服務(wù)器發(fā)起連接請求。參數(shù)

sockfd:套接字的文件描述符。

addr:服務(wù)器地址。

addrlen:地址長度。返回值 成功返回0,錯誤返回-1。接收數(shù)據(jù)頭文件

#include<sys/types.h> #include<sys/socket.h>函數(shù)原型

ssize_t

recv(int

sockfd,void*buf,size_t

len,intflags);

ssize_t

recvfrom(int

sockfd,void*buf,size_t

len,int

flags,struct

sockaddr*from,socklen_t*addrlen);

ssize_t

recvmsg(int

sockfd,struct

msghdr*msg,intflags);功能 從套接字接收數(shù)據(jù)。參數(shù)

sockfd:套接字的文件描述符。buff:緩沖區(qū)地址。

len:緩沖區(qū)大小。from:目標地址。addrlen:地址長度。

msg:接收請求地址。flags:選項。返回值 成功返回接收的字節(jié)數(shù),失敗返回-1。接收數(shù)據(jù)recv(sockfd,buf,len,flags);等價于:recvfrom(sockfd,buf,len,flags,NULL,NULL);。msg

為msghdr類型指針,可使函數(shù)參數(shù)最小化,msghdr類型封裝了接收數(shù)據(jù)所需的參數(shù),其定義如下。struct

msghdr{void*msg_name;//目標地址

socklen_t

msg_namelen;//目標地址長度

struct

iovec*msg_iov;//緩沖區(qū)

size_t

msg_iovlen;//緩沖區(qū)數(shù)量

void*msg_control;//附加數(shù)據(jù)地址

size_t

msg_controllen;//附加數(shù)據(jù)長度

int

msg_flags;//用于接收數(shù)據(jù)};發(fā)送數(shù)據(jù)頭文件 #include<sys/types.h> #include<sys/socket.h>函數(shù)原型

ssize_t

send(int

sockfd,constvoid*buf,size_t

len,intflags);

ssize_t

sendto(int

sockfd,constvoid*buf,size_t

len,int

flags,const

struct

sockaddr*to,socklen_t

addrlen);

ssize_t

sendmsg(int

sockfd,conststruct

msghdr*msg,intflags);功能

向套接字發(fā)送數(shù)據(jù)。參數(shù)

sockfd:套接字的文件描述符uff:緩沖區(qū)地址。

len:緩沖區(qū)大小。to:目標地址。addrlen:地址長度。

msg:發(fā)送請求。flags:選項。返回值 成功返回發(fā)送的字節(jié)數(shù),失敗返回-1。關(guān)閉連接頭文件

#include<unistd.h> #include<sys/socket.h>函數(shù)原型

int

close(int

sockfd);

int

shutdown(int

sockfd,inthow);功能 關(guān)閉/優(yōu)雅關(guān)閉連接。參數(shù)

sockfd:套接字的文件描述符。

how:關(guān)閉的方式。返回值 成功返回0,失敗返回-1。關(guān)閉連接

無須傳輸數(shù)據(jù)時,應(yīng)關(guān)閉連接,當向已關(guān)閉的套接字發(fā)送數(shù)據(jù)時,將導(dǎo)致失敗。當調(diào)用close函數(shù)關(guān)閉連接時,若套接字的內(nèi)核發(fā)送緩沖尚有未發(fā)送的數(shù)據(jù),close會一直等待,直至數(shù)據(jù)全部發(fā)送完成或超時。并非所有發(fā)生異常的一方都產(chǎn)生RST包,需通過其他手段獲知對方的狀態(tài)。優(yōu)雅關(guān)閉close函數(shù)會將收發(fā)兩條通道全部關(guān)閉,后續(xù)無法接收數(shù)據(jù);若使用shutdown函數(shù),可僅關(guān)閉寫通道,但仍可繼續(xù)接收數(shù)據(jù),故稱為優(yōu)雅關(guān)閉。收到FIN包的一方返回0,僅表示對方已關(guān)閉了寫操作,無法確定對方是否關(guān)閉了讀操作。無連接的傳輸協(xié)議UDPUDP為無連接的傳輸協(xié)議,無法保證將數(shù)據(jù)有序且正確地送達對方,但并不意味著丟報現(xiàn)象的頻繁發(fā)生,這取決于整個網(wǎng)絡(luò)的狀態(tài)。在局域網(wǎng)環(huán)境下,通常有很高的可靠性。相較于TCP,UDP消耗較少的帶寬資源,具有較高的傳輸效率。

UDP在很多應(yīng)用場景得到了廣泛應(yīng)用,例如,流媒體和網(wǎng)絡(luò)電話等。3基于UDP的客戶機/服務(wù)器模式請求數(shù)據(jù)socket()bind()recvfrom()服務(wù)器端socket()sendto()recvfrom()客戶機端(Blockuntilreceivedatagram)sendto()回復(fù)數(shù)據(jù)close()12.3Socket上的讀寫操作內(nèi)容提要socket支持文件I/O接口面向連接的I/O操作socket的異步驅(qū)動模式零拷貝技術(shù)字節(jié)序和字節(jié)對齊socket支持文件I/O接口

內(nèi)核為socket提供了文件I/O接口的支持,對于新建套接字時返回的套接字描述符,也適用于文件的I/O操作,例如,read/write函數(shù)和select/poll函數(shù)等。由于標準I/O函數(shù)庫建立在基本文件I/O基礎(chǔ)上,因此,標準I/O函數(shù)庫中的函數(shù)也適用于套接字,例如,fgets和fputs函數(shù)等,由于在用戶空間設(shè)置了緩沖區(qū),從而會給I/O讀寫操作帶來一定的影響。面向連接的I/O操作

由于面向連接套接字的字節(jié)流特性,數(shù)據(jù)的流速取決于雙方套接字內(nèi)核緩沖區(qū)滑動窗口狀態(tài)的變化,無論采用阻塞或非阻塞模式,在讀寫套接字時,未必能將指定大小的數(shù)據(jù)一次性操作成功。面向連接的讀操作

對于讀操作,造成無法一次性全部讀取所需數(shù)據(jù)的因素如下。1.所需的數(shù)據(jù)未全部到達內(nèi)核接收緩沖區(qū)。2.即使全部到達,在讀取過程也可能被信號中斷。面向連接的寫操作

對于寫操作,造成無法一次性全部寫入指定數(shù)據(jù)的因素如下。1.寫入過程被信號中斷。2.在非阻塞模式下,套接字的內(nèi)核發(fā)送緩沖區(qū)僅能容納部分待寫入的數(shù)據(jù)。一次性讀特定大小的數(shù)據(jù)ssize_t

readn(int

fd,void*buffer,size_tn){

ssize_t

numRead;

size_t

totRead; char*buf;

buf=buffer; for(totRead=0;totRead<n;){

numRead=read(fd,buf,n-totRead); if(numRead==0) returntotRead; if((numRead==-1)&&(errno==EINTR)) continue; else return-1;

totRead+=numRead;

buf+=numRead; } returntotRead;}一次性寫入特定大小的數(shù)據(jù)ssize_t

writen(int

fd,constvoid*buffer,size_tn){

ssize_t

numWritten;

size_t

totWritten; constchar*buf;

buf=buffer; for(totWritten=0;totWritten<n;){

numWritten=write(fd,buf,n-totWritten);if(numWritten<=0){ if(numWritten==-1&&errno==EINTR) continue; else return-1; }

totWritten+=numWritten;

buf+=numWritten; } returntotWritten;}socket的異步I/O模式

對處于非阻塞模式的套接字,為了獲知套接字狀態(tài)的變化,內(nèi)核提供了兩種異步I/O驅(qū)動模式。異步I/O事件驅(qū)動2.異步I/O信號驅(qū)動。異步I/O事件驅(qū)動

內(nèi)核將套接字狀態(tài)的改變抽象為I/O事件,例如,套接字上有新數(shù)據(jù)到達和發(fā)送緩沖區(qū)重新變得可用等,用戶可通過select/poll/epoll監(jiān)聽套接字狀態(tài)的變化,利用獲取的I/O事件判斷狀態(tài)改變的原因,從而進行相應(yīng)的處理,事件類型I/O事件I/O事件的描述readPOLLIN有數(shù)據(jù)到達readPOLLIN面向連接的請求到達readPOLLHUP對方關(guān)閉了連接readPOLLHUP向失效的套接字上寫數(shù)據(jù),同時發(fā)送SIGPIPE信號WritePOLLOUT發(fā)送緩沖區(qū)變得可用Read/WritePOLLIN|POLLOUT連接完成Read/WritePOLLERR發(fā)生了異步I/O錯誤Read/WritePOLLHUP對方關(guān)閉了一個方向上的通道ExceptionPOLLPRI緊急數(shù)據(jù)到達,同時發(fā)送SIGURG信號異步I/O信號驅(qū)動

若利用fcntl函數(shù)在套接字上設(shè)置了O_ASYNC標識,套接字則被設(shè)置為I/O信號驅(qū)動模式,當套接字的狀態(tài)發(fā)生改變,內(nèi)核會向指定的進程發(fā)送SIGIO信號或自定義的實時信號。當存在多個狀態(tài)發(fā)生改變的套接字,信號處理程序可根據(jù)信號來源加以區(qū)分。零拷貝技術(shù)

對于某些應(yīng)用,在數(shù)據(jù)傳輸時,需頻繁在用戶空間和內(nèi)核空間復(fù)制數(shù)據(jù),例如,web和ftp等。為了降低帶來的系統(tǒng)開銷,內(nèi)核引入了稱為零拷貝的技術(shù),直接在內(nèi)核完成數(shù)據(jù)復(fù)制,繞過了用戶緩沖區(qū),減少了數(shù)據(jù)拷貝次數(shù)。零拷貝接口函數(shù)sendfile函數(shù)頭文件

#include<sys/sendfile.h>函數(shù)原型

ssize_t

sendfile(int

out_fd,int

in_fd,off_t*offset,size_tcount);功能 在內(nèi)核空間傳輸文件。參數(shù)

out_fd:目標套接字的文件描述符。

in_fd:源文件描述符。

offset:偏移量。

count:數(shù)據(jù)的長度。返回值 成功返回實際拷貝的字節(jié)數(shù),失敗返回-1。字節(jié)序(1)小端模式小端模式是指將低字節(jié)存放在內(nèi)存的低地址處,例如,Intel80x86處理器采用該模式。(2)大端模式大端模式正好與小端模式相反,將高字節(jié)存放在內(nèi)存的低地址處,Motorola處理器采用這種模式,網(wǎng)絡(luò)字節(jié)序采用大端模式,字節(jié)序的存儲模式High-orderbyteLow-orderbyte高位16位/2字節(jié)

低位Low-orderbyteHigh-orderbyte地址增長的方向地址增長的方向AddressAAddressA+1小端模式大端模式AddressA+1AddressA字節(jié)對齊

理論上。任意類型的數(shù)據(jù)可存儲于內(nèi)存的任意位置,但出于效率等因素的考慮,某些處理器對數(shù)據(jù)的存儲地址有一定的要求,n字節(jié)對齊是指數(shù)據(jù)的存儲地址為n的整數(shù)倍,例如,對于IntelX86,簡單類型和結(jié)構(gòu)類型的存儲地址均為4的整數(shù)倍。12.4Unix域套接字Unix域概述Unix域是一種特殊的傳輸協(xié)議,用于本地進程間通信,支持面向連接和無連接兩種傳輸服務(wù)。在使用socket編寫服務(wù)器和庫戶籍時,僅協(xié)議族和地址類型有所不同。Unix域套接字1.創(chuàng)建Unix域套接字Unix_socket=socket(AF_UNIX,type,0);2.Unix域的地址struct

sockaddr_un{

sa_family_t

sun_family;//取值A(chǔ)F_UNIX charsun_path[108];//文件路徑};互聯(lián)套接字

為了便于本地關(guān)聯(lián)進程間通信,內(nèi)核引入了socketpair接口函數(shù)用于創(chuàng)建一對互聯(lián)套接字,通過它可實現(xiàn)父子進程或兩子進程間通信。相較于無名管道的單向數(shù)據(jù)傳輸互聯(lián)套接字可實現(xiàn)雙向數(shù)據(jù)傳輸。創(chuàng)建互聯(lián)套接字socketpair函數(shù)頭文件

#include<sys/socket.h>函數(shù)原型

int

socketpair(intdomain,inttype,intprotocol,intsv[2]););功能 創(chuàng)建一對互聯(lián)套接字。參數(shù)

domain:協(xié)議族。

type:協(xié)議類型。

protocol:子協(xié)議類型。

sv[2]:一對互聯(lián)套接字的文件描述符。返回值 成功返回0,失敗返回-1。12.5套接字選項套接字選項概述

每個套接字都有自身的行為屬性,它們決定了套接字在收發(fā)數(shù)據(jù)時的行為特征。為了滿足個性化需要,內(nèi)核引入了getsockopt/setsockopt接口函數(shù),用于獲取/設(shè)置套接字的選項,以便套接字的行為符合用戶的需求。獲取/設(shè)置套接字選項getsockopt/setsockopt函數(shù)頭文件

#include<sys/socket.h>函數(shù)原型

int

getsockopt(int

sockfd,int

level,int

optname,void*optval,socklen_t*optlen);

int

setsockopt(int

sockfd,int

level,int

optname,void*optval,socklen_t

optlen);功能 獲取/設(shè)置套接字選項。參數(shù)

sockfd:套接字的文件描述符。

Level:協(xié)議層類型。

optname:選項名稱。

optval:選項值。

optlen:optval占用的字節(jié)數(shù)。返回值 成功返回0,失敗返回-1。通用選項參數(shù)optname類型定義SO_BROADCASTBOOL允許/禁止發(fā)送廣播消息SO_DEBUGBOOL設(shè)置是否允許調(diào)試SO_DONTROUTEBOOL設(shè)置是否繞過正常的路由器SO_KEEPALIVEBOOL定時監(jiān)測連接是否處于活動狀態(tài)SO_LINGERLINGER關(guān)閉鏈接時的超時設(shè)置SO_OOBINLINEBOOL設(shè)置緊急數(shù)據(jù)放入普通數(shù)據(jù)流SO_RCVBUFint設(shè)置接收緩沖區(qū)的大小SO_REUSEADDRBOOL打開或關(guān)閉地址復(fù)用功能SO_RCVTIMEODWORD設(shè)置接收函數(shù)的超時時間(毫秒)SO_SNDBUFint設(shè)置發(fā)送緩沖區(qū)的大小

通用選項位于套接字接口層,是對各類協(xié)議接口的抽象,與特定的協(xié)議無關(guān),但并非通用選項適用于所有協(xié)議。LINGER選項

該選項用于定義關(guān)閉連接時的超時設(shè)置,選項值的類型定義如下。#including<sys/socket.h> structlinger{ intl_onoff;//0表示關(guān)閉,非0表示打開 intl_linger;//超時時間(秒)};LINGER選項(續(xù))若成員變量l_onoff置為0,內(nèi)核默認設(shè)置,該選項關(guān)閉,成員變量l_linger的值被忽略,close/shutdown立即返回,殘留在發(fā)送緩沖區(qū)的數(shù)據(jù)被丟棄。2.若成員變量l_onoff置為非0,l_linger設(shè)置超時時間,調(diào)用的close/shutdown函數(shù)掛起,直至內(nèi)核發(fā)送緩沖區(qū)的數(shù)據(jù)全部被對方確認或超時時間到期;若到期仍有未確認的數(shù)據(jù),則向

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論