Unix環(huán)境下的Socket編程講課講稿_第1頁(yè)
Unix環(huán)境下的Socket編程講課講稿_第2頁(yè)
Unix環(huán)境下的Socket編程講課講稿_第3頁(yè)
Unix環(huán)境下的Socket編程講課講稿_第4頁(yè)
Unix環(huán)境下的Socket編程講課講稿_第5頁(yè)
已閱讀5頁(yè),還剩9頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

1、un i x 環(huán) 境 下 的so c k e t 編 程精品資料僅供學(xué)習(xí)與交流,如有侵權(quán)請(qǐng)聯(lián)系網(wǎng)站刪除謝謝2unix 環(huán)境下的 socket 編程什么是 socket socket 接口是 tcp/ip 網(wǎng)絡(luò)的 api , socket 接口定義了許多函數(shù)或例程,程序員可以用它們來(lái)開(kāi)發(fā)tcp/ip 網(wǎng)絡(luò)上的應(yīng)用程序。要學(xué)in ternet 上的 tcp/ip 網(wǎng) 絡(luò)編程,必須理解 socket 接口。socket 接口設(shè)計(jì)者最先是將接口放在unix 操作系統(tǒng)里面的。如果了解unix 系統(tǒng)的輸入和輸出的話,就很容易了解socket 了。網(wǎng)絡(luò)的 socket 數(shù)據(jù)傳輸是一種特殊的 i/o,sock

2、et 也是一種文件描述符。 socket 也具有一個(gè)類似于打開(kāi)文件的函數(shù)調(diào)用 socket() ,該函數(shù)返回一個(gè)整型的socket 描述符,隨后的連接建立、數(shù)據(jù)傳輸?shù)炔僮鞫际峭ㄟ^(guò)該socket 實(shí)現(xiàn)的。常用的 socket 類型有兩種:流式socket ( sock_stream )和數(shù)據(jù)報(bào)式socket ( sock_dgram )。流式 是一種面向連接的 socket, 針對(duì)于面向連接的tcp 服務(wù)應(yīng)用;數(shù)據(jù)報(bào)式 socket 是一種無(wú)連接的socket, 對(duì)應(yīng)于無(wú)連接的 udp 服務(wù)應(yīng)用。socket 建立為了建立 socket ,程序可以調(diào)用 socket 函數(shù),該函數(shù)返回一個(gè)類似于文

3、件描述符的句柄。 socket 函數(shù)原型為:int socket(i nt doma in, int type, int protocol); domain 指明所使用的協(xié)議族,通常為pf_inet , 表示互聯(lián)網(wǎng)協(xié)議族(tcp/ip 協(xié)議族 ) ;type 參數(shù)指定 socket 的類型: sock_stream或sock_dgram ,socket 接口還定義了原始socket ( sock_raw ),允許程序 使用精品資料僅供學(xué)習(xí)與交流,如有侵權(quán)請(qǐng)聯(lián)系網(wǎng)站刪除謝謝3低層協(xié)議; protocol 通常賦值 0。socket() 調(diào)用返回一個(gè)整型socket 描述 符,你可以在后面的調(diào)用使

4、用它。socket 描述符是一個(gè)指向內(nèi)部數(shù)據(jù)結(jié)構(gòu)的指針,它指向描述符表入口。調(diào)用 socket 函數(shù)時(shí), socket 執(zhí)行體將建立一個(gè)socket ,實(shí)際上 建立一個(gè) socket 意味著為一個(gè) socket 數(shù)據(jù)結(jié)構(gòu)分配存儲(chǔ)空間。socket 執(zhí)行體為你管理描述符表。兩個(gè)網(wǎng)絡(luò)程序之間的一個(gè)網(wǎng)絡(luò)連接包括五種信息:通信協(xié)議、本地協(xié)議地址、本地主機(jī)端口、遠(yuǎn)端主機(jī)地址和遠(yuǎn)端協(xié)議端口。socket 數(shù)據(jù)結(jié)構(gòu)中包含這五種信息。socket 配置通過(guò) socket 調(diào)用返回一個(gè) socket 描述符后,在使用socket 進(jìn)行網(wǎng)絡(luò)傳輸以前,必須配置該 socketo 面向連接的 socket 客戶端通過(guò)

5、調(diào)用 connect 函數(shù)在 socket 數(shù)據(jù)結(jié)構(gòu)中保存本地和遠(yuǎn)端信息。無(wú)連接socket 的客戶端和服務(wù)端以及面向連接 socket 的服務(wù)端通過(guò)調(diào)用bind 函數(shù)來(lái)配置本地信息。bind 函數(shù)將 socket 與本機(jī)上的一個(gè)端口相關(guān)聯(lián),隨后你就可以在該端口監(jiān)聽(tīng)服務(wù)請(qǐng)求。bind 函數(shù)原型為:int bin d(i nt sockfd,struct sockaddr *my_addr, i nt addrle n); sockfd 是調(diào)用 socket 函數(shù)返回的 socket 描述符,my_addr 是一個(gè)指向包含有本機(jī) ip 地址及端口號(hào)等信息的 sockaddr 類型的指針; add

6、rlen 常被設(shè)置為sizeof(struct sockaddr 。精品資料僅供學(xué)習(xí)與交流,如有侵權(quán)請(qǐng)聯(lián)系網(wǎng)站刪除謝謝4struct sockaddri 吉構(gòu)類型是用來(lái)保存socket 信息的:struct sockaddr un sig ned short sa_family; /* 地址族,af_xxx */ char sa_data14; /* 14字節(jié)的協(xié)議地址*/ ;sa_family 一般為 af_inet ,代表 in ternet ( tcp/ip )地址族; sa_data 則包 含該 socket 的 ip 地址和端口號(hào)。另外還有一種結(jié)構(gòu)類型:struct sockaddr

7、 n short int sin_family; /* 地址族 */ un sig ned short int sin _port; /* 端口號(hào) */ struct in_addr sin _addr; /* ip 地址 */ unsigned char sin_zero8; /* 填充 0 以保持與struct sockaddr 同樣大小*/ ; 這個(gè)結(jié)構(gòu)更方便使用。sin_zero 用來(lái)將 sockaddr_in 結(jié)構(gòu)填充到與 struct sockaddr同樣的長(zhǎng)度,可以用bzero() 或 memset() 函數(shù)將其置為零。指向sockaddr_in 的指針和指向 sockaddr

8、的指針可以相互轉(zhuǎn)換,這意味著如果一個(gè)函數(shù)所需參數(shù)類型是sockaddr 時(shí),你可以在函數(shù)調(diào)用的時(shí)候?qū)⒁粋€(gè)指向sockaddr_in 的指針轉(zhuǎn)換為指向sockaddr 的指針;或者相反。使用 bind 函數(shù)時(shí),可以用下面的賦值實(shí)現(xiàn)自動(dòng)獲得本機(jī)ip 地址和隨機(jī)獲取一個(gè)沒(méi)有被占用的端口號(hào):my_addr.sin_port = 0; /* 系統(tǒng)隨機(jī)選擇一個(gè)未被使用的端口號(hào)*/ my_addr.sin_addr.s_addr = inaddr_any; /* 填入本機(jī)ip 地址 */ 精品資料僅供學(xué)習(xí)與交流,如有侵權(quán)請(qǐng)聯(lián)系網(wǎng)站刪除謝謝5通過(guò)將 my_addr.sin_port 置為 0, 函數(shù)會(huì)自動(dòng)為你

9、選擇一個(gè)未占用的端口來(lái)使用。同樣,通過(guò)將my_addr.sin_addr.s_add置為 inaddr_any ,系統(tǒng)會(huì)自動(dòng)填入本機(jī) ip 地址。注意在使用 bind 函數(shù)是需要將 sin_port 和 sin_addr 轉(zhuǎn)換成為網(wǎng)絡(luò)字節(jié)優(yōu)先順序;而sin_addr 則不需要轉(zhuǎn)換。計(jì)算機(jī)數(shù)據(jù)存儲(chǔ)有兩種字節(jié)優(yōu)先順序:高位字節(jié)優(yōu)先和低位字節(jié)優(yōu)先。in ternet上數(shù)據(jù)以高位字節(jié)優(yōu)先順序在網(wǎng)絡(luò)上傳輸,所以對(duì)于在內(nèi)部是以低位字節(jié)優(yōu)先方式存儲(chǔ)數(shù)據(jù)的機(jī)器, 在 in ternet 上傳輸數(shù)據(jù)時(shí)就需要進(jìn)行轉(zhuǎn)換, 否則就 會(huì)出現(xiàn)數(shù)據(jù)不一致。下面是幾個(gè)字節(jié)順序轉(zhuǎn)換函數(shù):? ton 1() : 把 32 位值從

10、主機(jī)字節(jié)序轉(zhuǎn)換成網(wǎng)絡(luò)字節(jié)序htons() : 把 16 位值從主機(jī)字節(jié)序轉(zhuǎn)換成網(wǎng)絡(luò)字節(jié)序ntohl() : 把 32 位值從網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)換成主機(jī)字節(jié)序ntohs() : 把 16 位值從網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)換成主機(jī)字節(jié)序bind() 函數(shù)在成功被調(diào)用時(shí)返回0; 出現(xiàn)錯(cuò)誤時(shí)返回 -1并將 errno 置為相應(yīng)的錯(cuò)誤號(hào)。需要注意的是,在調(diào)用bind 函數(shù)時(shí)一般不要將端口號(hào)置為小于1024的值,因?yàn)?1 到 1024 是保留端口號(hào),你可以選擇大于1024 中的任何一個(gè)沒(méi)有被占用的端口號(hào)。連接建立精品資料僅供學(xué)習(xí)與交流,如有侵權(quán)請(qǐng)聯(lián)系網(wǎng)站刪除謝謝6面向連接的客戶程序使用connect 函數(shù)來(lái)配置 socket

11、 并與遠(yuǎn)端服務(wù)器建立一個(gè)tcp 連接,其函數(shù)原型為:int conn ect(i nt sockfd, struct sockaddr *serv_addr,i nt addrle n); sockfd 是 socket 函數(shù)返回的 socket 描述符; serv_addr 是包含遠(yuǎn)端主機(jī)ip 地址和 端口號(hào)的指針; addrlen 是遠(yuǎn)端地質(zhì)結(jié)構(gòu)的長(zhǎng)度。 conn ect 函數(shù)在出現(xiàn)錯(cuò)誤時(shí)返回-1,并且設(shè)置 errno 為相應(yīng)的錯(cuò)誤碼。進(jìn)行客戶端程序設(shè)計(jì)無(wú)須調(diào)用bind(),因?yàn)檫@種情況下只需知道目的機(jī)器的ip 地址,而客戶通過(guò)哪個(gè)端口與服務(wù)器建立連接并不需要關(guān)心, socket 執(zhí)行體為

12、你的程序自動(dòng)選擇一個(gè)未被占用的端口,并通知你的程序數(shù)據(jù)什么時(shí)候到打斷口。co nnect 函數(shù)啟動(dòng)和遠(yuǎn)端主機(jī)的直接連接。只有面向連接的客戶程序使用socket時(shí)才需要將此 socket 與遠(yuǎn)端主機(jī)相連。無(wú)連接協(xié)議從不建立直接連接。面向連接的服務(wù)器也從不啟動(dòng)一個(gè)連接,它只是被動(dòng)的在協(xié)議端口監(jiān)聽(tīng)客戶的請(qǐng)求。listen 函數(shù)使 socket 處于被動(dòng)的監(jiān)聽(tīng)模式,并為該socket 建立一個(gè)輸入數(shù)據(jù)隊(duì)列,將到達(dá)的服務(wù)請(qǐng)求保存在此隊(duì)列中,直到程序處理它們。int listen(int sockfd , int backlog); sockfd 是 socket 系統(tǒng)調(diào)用返回的socket 描述符; b

13、acklog 指定在請(qǐng)求隊(duì)列中允許的最大請(qǐng)求數(shù),進(jìn)入的連接請(qǐng)求將在隊(duì)列中等待accept() 它們( 參考下文 )。backlog 對(duì)隊(duì)列中等待服務(wù)的請(qǐng)求的數(shù)目進(jìn)行了限制,大多數(shù)系統(tǒng)缺省值為20。如果一個(gè)服務(wù)請(qǐng)求到來(lái)時(shí),輸入隊(duì)列已滿,該socket 將拒絕連接請(qǐng)求,客精品資料僅供學(xué)習(xí)與交流,如有侵權(quán)請(qǐng)聯(lián)系網(wǎng)站刪除謝謝7戶將收到一個(gè)出錯(cuò)信息。當(dāng)出現(xiàn)錯(cuò)誤時(shí)listen 函數(shù)返回 -1, 并置相應(yīng)的 errno 錯(cuò) 誤碼。accept() 函數(shù)讓服務(wù)器接收客戶的連接請(qǐng)求。在建立好輸入隊(duì)列后,服務(wù)器就調(diào)用 accept 函數(shù),然后睡眠并等待客戶的連接請(qǐng)求。int accept(int sockfd,

14、void *addr, int *addrlen); sockfd 是被監(jiān)聽(tīng)的 socket 描述符, addr 通常是一個(gè)指向 sockaddr_in 變量的 指針,該變量用來(lái)存放提出連接請(qǐng)求服務(wù)的主機(jī)的信息( 某臺(tái)主機(jī)從某個(gè)端口發(fā)出該請(qǐng)求) ;addrten 通常為一個(gè)指向值為sizeof(struct sockaddr_in的整型指針變量。出現(xiàn)錯(cuò)誤時(shí) accept 函數(shù)返回 -1 并置相應(yīng)的 errno 值。首先,當(dāng) accept 函數(shù)監(jiān)視的 socket 收到連接請(qǐng)求時(shí), socket 執(zhí)行體將建立 一個(gè)新的 socket, 執(zhí)行體將這個(gè)新 socket 和請(qǐng)求連接進(jìn)程的地址聯(lián)系起來(lái),

15、收到服務(wù)請(qǐng)求的初始 socket 仍可以繼續(xù)在以前的socket 上監(jiān)聽(tīng),同時(shí)可以在新的socket 描述符上進(jìn)行數(shù)據(jù)傳輸操作。數(shù)據(jù)傳輸send( 和 recv()這兩個(gè)函數(shù)用于面向連接的socket 上進(jìn)行數(shù)據(jù)傳輸。se nd() 函數(shù)原型為:int send(int sockfd, const void *msg, int len, int flags); sockfd 是你想用來(lái)傳輸數(shù)據(jù)的socket 描述符; msg 是一個(gè)指向要發(fā)送數(shù)據(jù)的指針;精品資料僅供學(xué)習(xí)與交流,如有侵權(quán)請(qǐng)聯(lián)系網(wǎng)站刪除謝謝8len 是以字節(jié)為單位的數(shù)據(jù)的長(zhǎng)度;flags 一般情況下置為 0 ( 關(guān)于該參數(shù)的用法可

16、參照 man 手冊(cè)) 。se nd( 函數(shù)返回實(shí)際上發(fā)送出的字節(jié)數(shù),可能會(huì)少于你希望發(fā)送的數(shù)據(jù)。在程序中應(yīng)該將 send() 的返回值與欲發(fā)送的字節(jié)數(shù)進(jìn)行比較。當(dāng)send()返回值與len 不匹配時(shí),應(yīng)該對(duì)這種情況進(jìn)行處理。char *msg = hello!; int len, bytes_se nt; len = strle n(msg); bytes_se nt = sen d(sockfd, msg,le n, 0); recv()函數(shù)原型為:int recv(i nt sockfd,void *buf,i nt len,un sig ned int flags); sockfd 是接

17、受數(shù)據(jù)的 socket 描述符; buf 是存放接收數(shù)據(jù)的緩沖區(qū);len 是 緩沖的長(zhǎng)度。 flags 也被置為 0。recv() 返回實(shí)際上接收的字節(jié)數(shù),當(dāng)出現(xiàn)錯(cuò)誤時(shí),返回-1 并置相應(yīng)的 errno 值。sendto() 和 recvfrom() 用于在無(wú)連接的數(shù)據(jù)報(bào)socket 方式下進(jìn)行數(shù)據(jù)傳輸。由于本地socket 并沒(méi)有與遠(yuǎn)端機(jī)器建立連接,所以在發(fā)送數(shù)據(jù)時(shí)應(yīng)指明目的地址。sen dto() 函數(shù)原型為:int sen dto(i nt sockfd, const void *msg,i nt le n,un sig ned int flags,c onst struct socka

18、ddr *to, int tole n); 該函數(shù)比 send() 函數(shù)多了兩個(gè)參數(shù), to 表示目地機(jī)的 ip 地址和端口號(hào)信精品資料僅供學(xué)習(xí)與交流,如有侵權(quán)請(qǐng)聯(lián)系網(wǎng)站刪除謝謝9息,而 tolen 常常被賦值為 sizeof (struct sockaddr 。sendto 函數(shù)也返回實(shí)際發(fā)送的數(shù)據(jù)字節(jié)長(zhǎng)度或在出現(xiàn)發(fā)送錯(cuò)誤時(shí)返回-1。recvfro m() 函數(shù)原型為:int recvfrom(i nt sockfd,void *buf,i nt len,un sig ned int flags,struct sockaddr *from,i nt *fromle n); from 是一個(gè)

19、struct sockaddr 類型的變量,該變量保存源機(jī)的ip 地址及端口號(hào)。fromlen 常置為 sizeof (struct sockaddr 。當(dāng) recvfrom() 返回時(shí), fromlen 包含 實(shí)際存入 from 中的數(shù)據(jù)字節(jié)數(shù)。recvfrom() 函數(shù)返回接收到的字節(jié)數(shù)或當(dāng)出現(xiàn)錯(cuò)誤時(shí)返回-1,并置相應(yīng)的errno。如果你對(duì)數(shù)據(jù)報(bào) socket 調(diào)用了 connect() 函數(shù)時(shí),你也可以利用send()和 recv()進(jìn)行數(shù)據(jù)傳輸,但該socket 仍然是數(shù)據(jù)報(bào) socket, 并且利用傳輸層的udp 服務(wù)。 但在發(fā)送或接收數(shù)據(jù)報(bào)時(shí),內(nèi)核會(huì)自動(dòng)為之加上目地和源地址信息。結(jié)

20、束傳輸當(dāng)所有的數(shù)據(jù)操作結(jié)束以后,你可以調(diào)用close() 函數(shù)來(lái)釋放該 socket, 從而停止在該 socket 上的任何數(shù)據(jù)操作:close(sockfd); 你也可以調(diào)用 shutdown() 函數(shù)來(lái)關(guān)閉該 socket。該函數(shù)允許你只停止在某個(gè)方向上的數(shù)據(jù)傳輸,而一個(gè)方向上的數(shù)據(jù)傳輸繼續(xù)進(jìn)行。如你可以關(guān)閉某socket 的寫操作而允許繼續(xù)在該socket 上接受數(shù)據(jù),直至讀入所有數(shù)據(jù)。精品資料僅供學(xué)習(xí)與交流,如有侵權(quán)請(qǐng)聯(lián)系網(wǎng)站刪除謝謝10int shutdow n(i nt sockfd,i nt how); sockfd 是需要關(guān)閉的 socket 的描述符。參數(shù) how 允許為 s

21、hutdown 操作選擇以下幾種方式:0 - 不允許繼續(xù)接收數(shù)據(jù)1 - 不允許繼續(xù)發(fā)送數(shù)據(jù)2 - 不允許繼續(xù)發(fā)送和接收數(shù)據(jù),?均為允許則調(diào)用close () shutdown 在操作成功時(shí)返回0, 在出現(xiàn)錯(cuò)誤時(shí)返回 -1 并置相應(yīng) errno。面向連接的 socket 實(shí)例代碼實(shí)例中的服務(wù)器通過(guò)socket 連接向客戶端發(fā)送字符串hello, you are connected! 。只要在服務(wù)器上運(yùn)行該服務(wù)器軟件,在客戶端運(yùn)行客戶軟件,客戶端就會(huì)收到該字符串。該服務(wù)器軟件代碼如下:#i nclude #i nclude #i nclude #i nclude精品資料僅供學(xué)習(xí)與交流,如有侵權(quán)請(qǐng)聯(lián)

22、系網(wǎng)站刪除謝謝11#i nclude #i nclude #i nclude #i nclude #defi ne servport 3333 /* 服務(wù)器監(jiān)聽(tīng)端口號(hào) */ #define backlog 10 /* 最大同時(shí)連接請(qǐng)求數(shù) */ mai n() int sockfd,client_fd; /*sock_fd : 監(jiān)聽(tīng) socket; client_fd : 數(shù)據(jù)傳輸socket */ struct sockaddr_in my_addr; /* 本機(jī)地址信息*/ struct sockaddr_in remote_addr; /*客戶端地址信息 */ if (sockfd = s

23、ocket(af net, sock_stream, 0) = -1) perror(socket 創(chuàng)建出錯(cuò)!); exit(1); my_addr.si n_family=af n et; my_addr.sin_port=hto ns(servport); my_addr.sin_addr.s_addr = inaddr_any; bzero(&(m y_addr.sin_zero),8); if (bin d(sockfd, (struct sockaddr *)&m y_addr, sizeof(struct sockaddr) =-1) 精品資料僅供學(xué)習(xí)與交流,如有侵

24、權(quán)請(qǐng)聯(lián)系網(wǎng)站刪除謝謝12perror(bind 出錯(cuò)! ); exit(1); if (liste n(sockfd, backlog) = -1) perror(listen 出錯(cuò)! ); exit(1); while(1) sin_size = sizeof(struct sockaddr_i n); if (clie nt_fd = accept(sockfd, (struct sockaddr *)&remote_addr, & sin_size) = -1) perror(accept 出錯(cuò)); con ti nue; prin tf(received a connection from %sn, inet_n toa(remote_addr.s in _addr); if (!fork() /* 子進(jìn)程代碼段 */ if (send(client_fd, hello, you are connected!n, 26, 0) = -1) perror(send 出錯(cuò)! ); close(clie nt_fd); exit(o); 精品資料僅供學(xué)習(xí)與交流,如有侵權(quán)請(qǐng)聯(lián)系網(wǎng)站刪除謝謝13 close(clie nt_fd); 服務(wù)器的工作流程是這樣的:首先調(diào)用socket 函數(shù)創(chuàng)建一個(gè) socket , 然后調(diào)用 bind 函數(shù)將其與本

溫馨提示

  • 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ì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論