實驗六_TCP、UDP通信程序設計實驗.ppt_第1頁
實驗六_TCP、UDP通信程序設計實驗.ppt_第2頁
實驗六_TCP、UDP通信程序設計實驗.ppt_第3頁
實驗六_TCP、UDP通信程序設計實驗.ppt_第4頁
實驗六_TCP、UDP通信程序設計實驗.ppt_第5頁
已閱讀5頁,還剩34頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

1、實驗六 TCP、UDP通信程序設計實驗,2,客戶1,客戶2,服務器,請求,應答,請求,應答,通信程序基礎:客戶端和服務器,3,IPv4, IPv6,Ethernet Adapter,App1,App2,port A,port B,TCP,UDP,通信程序基礎:分層,4,TCP通信實驗cont1,5, 得到ip地址 建立tcp連接: 構(gòu)造http數(shù)據(jù)包,向tcp請求 構(gòu)造tcp數(shù)據(jù)包,承載http包 構(gòu)造ip數(shù)據(jù)包 得到mac地址 構(gòu)造數(shù)據(jù)幀,通信程序基礎:實例,6,7,Socket介紹(1),什么是socket? 先看文件操作的例子: 通過open函數(shù)得到一個文件的文件描述符;然后對這個描述符

2、進行讀寫,得到一個整數(shù)來標識這個文件,稱為file descriptor,得到一個整數(shù)來標識這個文件,把用來標識這個文件整數(shù)看作是這個入口的標識,把用來標識這個文件的整數(shù)看作是這兩入口的標識,8,Socket介紹(2),socket,socket,Socket descriptor,用類似于open的函數(shù)得到一個socket 描述符,然后對這個描述符進行讀寫操作,9,從網(wǎng)絡整體來看,socket是不同主機上應用程序之間的一個虛擬的接口,具有跨平臺特性。 從程序員角度來看,它是應用程序和網(wǎng)絡設備的一個接口,特殊的I/O 從操作系統(tǒng)看,它是一種資源。如同handle用來描述windows中的窗口等

3、資源,socket用socket descriptor來標識。,Socket介紹(3),10,字節(jié)流套接口(Stream Sockets) 面向連接的,位于TCP之上 數(shù)據(jù)報套接口(Datagram Sockets) 無連接的,位于UDP之上 原始套接口(Raw Sockets) 直接發(fā)送和處理IP包:例如ping,Socket介紹(4),11,Socket的起源 最初在70年代由加州大學Berkeley分校開發(fā),其目的是為BSD(Berkeley Software Distribution) UNIX 4.1版操作系統(tǒng)提供網(wǎng)絡通信接口。 Socket在各種平臺下的發(fā)展 隨著Berkeley

4、Sockets的廣泛應用,九十年代初,Sun、MS等公司共同制定了適應dos和win平臺的windows sockets的規(guī)范(WinSock) Sun Microsystems為Java也制定了網(wǎng)絡通信的API Linux下的socket繼承了BSD sockets的風格,并有所改動 不同的網(wǎng)絡有不同的套接口 CCITT X.25套接口 Berkeley 套接口,Socket介紹(5),12,現(xiàn)在開始具體介紹socket編程。 由前面的敘述可以看出,我們要進行通信就要得到對應的socket descriptor,一旦得到了,對它進行讀寫操作就可以了,例如 int read( int fd,

5、char *buf, int len); int write(int fd, char *buf, int len); 在與另一臺計算機通信之前要知道對方的什么信息? IP地址或者域名 端口(用來區(qū)分不同的應用),Socket介紹(6),13,Socket用下面的結(jié)構(gòu)體來描述一個IP地址socket.h 結(jié)構(gòu)中sa_family為套接口的協(xié)議族地址類型,例如對于通常的TCP/IP協(xié)議(IPv4),它的值是AF_INET; sa_data中存儲著具體的協(xié)議地址,不同的協(xié)議族有不同的地址格式。 sa_data的存儲內(nèi)容往往是包含地址和端口信息,而僅使用一個變量,使用起來不太方便定義新的Socket

6、地址結(jié)構(gòu),Socket介紹(7),struct sockaddr unsigned short sa_family; /* 地址家族2字節(jié)*/ char sa_data14; /*14字節(jié)協(xié)議地址*/ ;,14,新版的socket地址的定義 最后的那個元素是填充的空白信息, 這樣就保持整個結(jié)構(gòu)與sockaddr結(jié)構(gòu)的長度相同,Socket介紹(8),struct sockaddr_in short int sin_family; /* 通信類型2字節(jié) */ unsigned short int sin_port; /* 端口, 2字節(jié)*/ struct in_addr sin_addr; /*

7、 Internet 地址, 4字節(jié)*/ unsigned char sin_zero8; ,注意理解指針和類型強制轉(zhuǎn)換,15,Socket介紹(9),structin_addr unsigned long s_addr; ;,圖中的紫色部分就是端口和IP地址。這兩個域必須是網(wǎng)絡字節(jié)順序 NetworkByteOrder,struct sockaddr_in short int sin_family; /* 通信類型2字節(jié) */ unsigned short int sin_port; /* 端口, 2字節(jié)*/ struct in_addr sin_addr; /* Internet 地址, 4

8、字節(jié)*/ unsigned char sin_zero8; ,16,struct in_addr union struct unsigned char s_b1; unsigned char s_b2; unsigned char s_b3; unsigned char s_b4; S_un_b; struct unsigned short s_w1; unsigned short s_w2; S_un_w; unsigned long S_addr; S_un; ;,17,sockaddr只是一個抽象的概況形式,并不實用 sockaddr_in更加結(jié)合了TCP/IP協(xié)議族的特點,易于使用,所

9、以編程中常使用這個結(jié)構(gòu)。 但是:socket本身所封裝的API都是支持sockaddr結(jié)構(gòu)的,所以填充sockaddr_in結(jié)構(gòu)需要強制轉(zhuǎn)換成sockaddr結(jié)構(gòu),方可作為參數(shù)被socket的標準函數(shù)所使用。例如: int connect( int sockfd, struct sockaddr * servaddr, unsigned int addrlen),Socket介紹(10),18,字節(jié)順序 主機字節(jié)順序(Host Byte Order) 低位在前,高位在后(little-endian) 基于Intel芯片的機器采取這種存儲方式 網(wǎng)絡字節(jié)順序(Network Byte Order)

10、 高位在前,低位在后(big-endian) Sockaddr_in的變量成員(端口和地址)都必須使用網(wǎng)絡字節(jié)順序,字節(jié)順序,19,例如端口34567的16進制表示是0 x8707。如果定義變量unsigned short sin_port = 34567,0 x11111111,0 x11111112,主機字節(jié)序,.68 1f e3 34 87 07 36.,網(wǎng)絡字節(jié)序,以字節(jié)為最小單位,但是計算機對內(nèi)存的讀取是雙字節(jié)的,如果是ip地址1的16進制表示。如果定義變量unsigned long s_addr = 0 xCA264B0B,0 x22222222,0 x222

11、22225,0B,4B,26,CA,.68 1f CA 26 4B 0B 12.,20,字節(jié)順序,轉(zhuǎn)換字節(jié)順序的函數(shù)(in.h),uint16_t htons(uint16_t); uint16_t ntohs(uint_16_t); uint32_t htonl(uint32_t); uint32_t ntohl(uint32_t);,h : host n : network s : short (16bit) l : long (32bit),例如:定義struct sockaddr_in sh; unsigned short port = 12345; sh.sin_port = hto

12、ns(port);,htons和ntohs的實現(xiàn)是一樣的;htonl和ntohl一樣,21,前面提到的幾個函數(shù)對于IP地址的轉(zhuǎn)換仍然不方便,因為首先得得到ip地址的數(shù)值表示,而我們習慣于用帶點的字符串來表示,如“1” 因此希望有函數(shù)能處理這樣的請求: 給一個字符串如“1”能返回相應的網(wǎng)絡字節(jié)序的unsigned long值 給一個unsigned long的值能返回一個字符串,字節(jié)順序,22,inet_aton int inet_aton(const char *cp, struct in_addr *inp); 例如將“0”轉(zhuǎn)

13、化為0 xC0A8000A inet_addr unsigned long inet_addr(const char *cp); 功能同上,但不能處理廣播地址 inet_ntoa char * inet_ntoa(struct in_addr in); 例如將0 xC0A8000A轉(zhuǎn)化為“0”,23,TCP通信實驗,注意bind和listen,socket(),bind(),listen(),accept(),write(),read(),read(),TCP Server,close(),socket(),TCP Client,connect(),write(),rea

14、d(),close(),建立連接,客戶請求,服務器響應,結(jié)束連接,24,基本套接口函數(shù)(1)- socket(),int fd; /* socket descriptor */ if (fd = socket(AF_INET, SOCK_STREAM, 0) 0) fprintf(stderr,“socket creating errorn”); exit(1); /*注:在TCP或UDP編程的時候,protocol都取0*/,#include int socket(int domain, int type, int protocol); 創(chuàng)建socket 返回:非負整數(shù)描述符表示成功,-1表

15、示出錯 domain一般設為AF_INET,protocol一般設為0,25,基本套接口函數(shù)(2)- connect(),#include int connect(int sockfd, struct sockaddr * servaddr, unsigned int addrlen); 返回:0表示成功,-1表示出錯,connect()由客戶使用, 旨在和服務器建立一個連接。sockfd是函數(shù)socket()返回的套接口描述符, servaddr表示遠程服務器的套接口, addrlen表示套接口地址的長度 注意:之前要先調(diào)用socket()創(chuàng)建套接口,26,TCP通信- 客戶端例子,int

16、fd;/* 套接口描述符 */ struct sockaddr_in srv;/* 套接口地址結(jié)構(gòu) */ fd = socket(AF_INET, SOCK_STREAM, 0); /* connect: AF_INET表示使用Internet地址族 */ srv.sin_family = AF_INET; /* connect: 目標是連向服務器的 8000 號端口 */ srv.sin_port = htons(8000); /* connect: 目標服務器的 IP Address 是 “1” */ srv.sin_addr.s_addr = inet_addr(“

17、1”); if(connect(fd, (struct sockaddr*) ,27,基本套接口函數(shù)(3)- bind(),#include int bind(int sockfd, struct sockaddr * servaddr, unsigned int addrlen); 返回:0表示成功,-1表示出錯,bind將本機地址(某個或全部地址)與套接口綁定在一起 一般用于服務器綁定自己公認的服務端口號 客戶端一般會在調(diào)用connect函數(shù)時,系統(tǒng)自動為客戶 選擇一個大于1024的端口號,并用客戶本地IP地址填充 套接口地址中的相關項,28,基本套接口函數(shù)(4)-

18、listen(),#include int listen(int sockfd, int backlog); 返回:0表示成功,-1表示出錯,listen只被TCP服務器所使用! 函數(shù)listen將一個套接口轉(zhuǎn)換為偵聽套接口(listening socket), 因為每個套接口在創(chuàng)建的時候都是主動套接口,等待使用connect函數(shù)發(fā)起連接。而listen將套接口轉(zhuǎn)化為被動的,指示內(nèi)核應接收來自此套接口的連接請求。 backlog參數(shù)指示了內(nèi)核為此套接口排隊的最大連接數(shù)目,29,基本套接口函數(shù)(5)- accept(),#include int accept(int sockfd, struct

19、 sockaddr * addr, unsigned int * addrlen); 返回:非負描述符表示成功,-1表示出錯,函數(shù)accept由TCP服務器在listen函數(shù)之后調(diào)用, 它從偵聽的套接口的完成連接隊列中接收一個連接, 若已完成連接為空, 那么該進程進入睡眠, 處于等待連接的方式 參數(shù)sockfd指定偵聽的套接口描述符, addr和addrlen用以返回與服務器相連接的客戶的協(xié)議地址信息, 如果對客戶地址和端口感興趣, 則可以從addr中提取相關信息 函數(shù)accpet最終返回一個新的套接口描述符, 以標識連接,該函數(shù)是阻塞型的!,30,基本套接口函數(shù)(6)- 其它,#includ

20、e int read( int fd, char *buf, int len); 返回實際接收的緩沖區(qū)大小 int write(int fd, char *buf, int len); 返回實際發(fā)送的緩沖區(qū)大小 int close(int sockfd); int closesocket(int sockfd); 成功返回0, 否則返回-1 還有一些其他的發(fā)送接收函數(shù), 感興趣者可以查閱幫助,31,TCP通信- 服務器例子,int fd;/* 套接口描述符 */ struct sockaddr_in srv;/* 套接口地址結(jié)構(gòu) */ fd = socket(AF_INET, SOCK_STR

21、EAM, 0) /* AF_INET表示使用Internet地址族 */ srv.sin_family = AF_INET; /* 將socket綁定到 8000 號端口,將主機存儲方式轉(zhuǎn)化為網(wǎng)絡存儲方式 */ srv.sin_port = htons(8000); /* bind: INADDR_ANY 表示服務器將接收來自本機上任何一塊網(wǎng)卡的客戶連接 將主機存儲方式轉(zhuǎn)化為網(wǎng)絡存儲方式 */ srv.sin_addr.s_addr = htonl(INADDR_ANY); if(bind(fd, (struct sockaddr*) ,32,if(listen(fd, 5) 0) fprin

22、tf(stderr, ”listen error!n); exit(1); newfd = accept(fd, (struct sockaddr*) ,TCP通信- 服務器例子(續(xù)),33,要求使用linux編寫通信程序 Linux下,寫好源代碼后,gcc file.c o xxx;運行則用./xxx 每調(diào)用一個函數(shù)要進行錯誤檢查及處理 例如 if(listen(fd, 5) 0) socket用完之后要調(diào)用close關閉連接 進一步的思考 程序的水平取決于連接建立后的讀寫操作的設計,當然良好的用戶界面也很重要 accept函數(shù)是一個阻塞型函數(shù)多線程的用武之地,實驗二、TCP、UDP通信程序

23、設計實驗TCP通信實驗注意事項,34,35,UDP通信實驗,socket(),bind(),recvfrom(),sendto(),UDP Server,socket(),UDP Client,sendto(),recvfrom(),close(),阻塞,直到接收到 客戶發(fā)送過來的數(shù)據(jù)報,data request,data reply,36,基本套接口函數(shù)(7),#include int recvfrom(int sockfd, void * buf, int len, int flags, struct sockaddr * from, unsigned int *addrlen); int sendto(int sockfd, const void * msg, int len, int flags, const struct sockaddr * to, unsigned int addrlen);,與TCP不同的是, UDP在通信時, 系統(tǒng)內(nèi)部不記錄套接口地址信息, 都是函數(shù)中主動以參數(shù)的形式指明的. 在TCP情況下, 客戶connect成功后(服務器accept成功后), 每次發(fā)送接收都只需指定套接口描述符就行了, 但是這里每次發(fā)送接收都需要額外附加上對方的套接口地址信息.,阻塞

溫馨提示

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

評論

0/150

提交評論