1、2018/8/11,1,Socket 概論與基本架構,2018/8/11,2,Outline,Network BasicsSocket BasicsTCP SocketUDP Socket,2018/8/11,3,OSI Model,2018/8/11,4,協定分層,實體層 (Physical layer) 這層是OSI模型最下面的階層,在這一層主要是負責產生電流或光脈衝,將資料經過網路卡等界送到網路媒介上 資料連接層 (Data link layer) 在這一層指定了所採用的訊號單元是什麼,以及它們的格式、和如何通過網路。 在每個封包上會有一個位址碼和偵錯監測值,2018/8/11,5,協定
2、分層,網路層 (Network layer) 負責邏輯位址和實體位址轉換,以及處理分封交換網路上的節點間之路由 它可基於網路狀況、資料優先性等因素來決定資料的走向,以及管理封包交換、決定路徑、控制網路上封包的數量等等 傳輸層 (Transport layer) 負責分封和重組並利用流量控制以及同步控制的方式來負責接狀兩端之間傳送訊息的可靠度。,2018/8/11,6,協定分層,會議層 (Session layer) 負責讓兩台電腦上的應用程式能建立、使用、並終止連線。 展現層 (Presentation layer) 決定了兩台網路上的電腦交換資料的方法 應用層 (Application la
3、yer) 在網路上執行的應用程式可以直接與其下面的階層通訊,2018/8/11,7,TCP/IP Model,應用層 (Application layer),傳輸層 (Transport layer),網路層 (Network layer),網路介面層 (Network Interface layer),2018/8/11,8,TCP/IP模型與OSI模型之對應,2018/8/11,9,Sockets 界面所使用的通訊埠,Application,Transport,Network,Network interface,2018/8/11,10,Process Model,當上層軟體要將一個訊息傳
4、到網路時,可以用兩種模型來表示訊息處理的模型:,Process-per-Protocol,Process-per-Message,2018/8/11,11,Process-per-Protocol model,在這種模型中,系統以不同的處理程序來完成每個抽象層的工作。 優點: 因為將整體程序切割為幾個主要的部分,對程序開發者而言,是容易維護以及修改 缺點: 因為傳出的訊息從上層到底層須要經許多不同程序處理,也因此引入許多context switching的機會。增加許多overhead,2018/8/11,12,Process-per-Message,在此種模型中,系統以一個整體程序來完成所有
5、分層的工作。 優點:沒有context switching的overhead 缺點:程式過於龐大,不易開發維護及更新。,2018/8/11,13,Socket 概論,Socket機制是在1982年首次出現在4.1BSD UNIX中。 直到1990年,socket介面在4.3BSD Reno版中對socket位址結構進行些微的改變 兩個位元組長的通訊協定族群欄被分成兩欄,其中一欄是一位元組長的長度欄位,另一個是一位元組長的通訊協定族群欄,以及一些為支援ISO的通訊協定而做的改變。 Socket設計的目的是提供處理程序一個一致的通訊設施,不論這些處理程序是否在同一台機器上。,2018/8/11,1
6、4,Socket 概論,2018/8/11,15,基本架構,Socket 的架構大體上可分為兩大部份 Main程式部份:用來建立所要的連線(TCP/IP、UDP) 處理程式部份:用來宣告連線後的處理工作 而在伺服端和客戶端呼叫主程式部份大致相同,副程式則因其所需的工作不同而不同。 以一簡單的daytime 伺服端客戶端例子來說明之,2018/8/11,16,簡單的daytime 客戶端,#include “unp.h“int main(int argc, char *argv) int sockfd, n;char recvlineMAXLINE + 1;struct sockaddr_in
7、servaddr;if (argc != 2)err_quit(“usage: a.out “);if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0) 0)err_sys(“socket error“);,2018/8/11,17,簡單的daytime 客戶端,bzero(,2018/8/11,18,簡單的daytime 客戶端,while ( (n = read(sockfd, recvline, MAXLINE) 0) recvlinen = 0; /* null terminate */if (fputs(recvline, stdout) = E
8、OF)err_sys(“fputs error“);if (n 0)err_sys(“read error“);exit(0); ,2018/8/11,19,簡單的daytime 伺服端,#include “unp.h“ #include int main(int argc, char *argv) int listenfd, connfd;struct sockaddr_in servaddr;char buffMAXLINE;time_t ticks;listenfd = Socket(AF_INET, SOCK_STREAM, 0);,2018/8/11,20,簡單的daytime 伺服
9、端,bzero(,2018/8/11,21,簡單的daytime 伺服端,for ( ; ; ) connfd = Accept(listenfd, (SA *) NULL, NULL);ticks = time(NULL);snprintf(buff, sizeof(buff), “%.24srn“, ctime( ,2018/8/11,22,TCP socket 基礎,2018/8/11,23,TCP客戶與伺服端的運作流程圖,TCP伺服端,2018/8/11,24,TCP的基本socket函式,進行網路I/O前,行程必須先呼叫socket函式 Socket函式 #include int s
10、ocket (int family, int type, int protocol) ; family參數是要指定協定家族,2018/8/11,25,Socket函式,type參數是socket函式的socket類型protocol參數通常設為0,除低階socket外,Socket 函式中 family 與 type 參數的組合,type 的類型,2018/8/11,26,Connect 函式,TCP客戶端使用connect函式來建立與TCP伺服端的連線 #include int connect (int sockfd, const struct sockaddr *servaddr, sok
11、len_t addrlen) ; sockfd 是 socket 函式傳回的socket descriptor 而第二、三個參數則是socket位址結構的指標及其長度,2018/8/11,27,Bind 函式,bind 函式會將本機協定位址指定給socket;在Internet協定中的協定位址是32位元的IPv4位址、或128位元的IPv6位址,加上16位元的TCP或UDP埠號。 #include int bind (int sockfd, const struct sockaddr *myaddr, socklen_t addlen) ; 第二個參數是特定協定位址的指標 第三個參數則是該位址
12、結構的長度 在TCP中,呼叫bind可以單獨指定埠號、IP位址兩者、或都不指定,2018/8/11,28,Bind 函式 (cont.),在bind中指定IP位址及埠號的結果,2018/8/11,29,Listen 函式,#include int listen (int sockfd, int backlog) ; 只有TCP伺服端會呼叫listen函式,會進行2項動作 當socket函式建立socket時,會被假設為主動式socket。Listen函式則會將未被連線的socket轉換為被動式socket,指示kernel應該接受針對這個socket進入的連線請求。 函式的第2個參數會指定ke
13、rnel應該為此socket暫存到佇列中的最大連線數目。,2018/8/11,30,Accept函式,TCP伺服端會呼叫accept,從已完成連線佇列最前端傳回下個已完成的連線。如果已完成連線佇列是空的,行程就會進入睡眠 #include int accept (int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen) ; cliaddr與addrlen參數是用來傳回連線客戶端的協定位址;addrlen是值一結果參數:在呼叫前,將*addrlen指向的整數值設為cliaddr指向之socket位址結構的長度;在傳回時,整數值會包含ker
14、nel在socket位址結構中實際存放的位元組數目。,2018/8/11,31,Close 函式,用來關閉socket,並且終止TCP連線 #include int close (int sockfd) ;,2018/8/11,32,TCP主從式程式範例,使用echo為一簡單範列,其執行步驟如下: 客戶端從標準輸入讀取一列文字,然後將該文字列送給伺服端。 伺服端從它的網路輸入中讀取資料列,然後將該列反彈回去給客戶端。 客戶端會讀取回傳的資料列,並且列印至標準輸出。,fgets,2018/8/11,33,TCP Echo伺服端:main函式,#include “unp.h“int main(in
15、t argc, char *argv) int listenfd, connfd;pid_t childpid;socklen_t clilen;struct sockaddr_in cliaddr, servaddr;listenfd = socket(AF_INET, SOCK_STREAM, 0);bzero(,2018/8/11,34,TCP Echo伺服端:main函式 (cont.),Bind(listenfd, (SA *) /* parent closes connected socket */ ,2018/8/11,35,TCP Echo伺服端:str_echo函式,#inc
16、lude “unp.h“void str_echo(int sockfd) ssize_t n;char lineMAXLINE;for ( ; ; ) if ( (n = Readline(sockfd, line, MAXLINE) = 0)return; /* connection closed by other end */Writen(sockfd, line, n); ,2018/8/11,36,TCP Echo客戶端:main函式,#include “unp.h“int main(int argc, char *argv) int sockfd;struct sockaddr_i
17、n servaddr;if (argc != 2)err_quit(“usage: tcpcli “);sockfd = Socket(AF_INET, SOCK_STREAM, 0);bzero(,2018/8/11,37,TCP Echo客戶端:main函式 (cont.),Connect(sockfd, (SA *) ,2018/8/11,38,TCP Echo客戶端:str_cli函式,#include “unp.h“void str_cli(FILE *fp, int sockfd) char sendlineMAXLINE, recvlineMAXLINE;while (Fgets
18、(sendline, MAXLINE, fp) != NULL) Writen(sockfd, sendline, strlen(sendline);if (Readline(sockfd, recvline, MAXLINE) = 0)err_quit(“str_cli: server terminated prematurely“);Fputs(recvline, stdout); ,2018/8/11,39,UDP socket 基礎,2018/8/11,40,UDP客戶與伺服端的運作流程,UDP客戶端,socket ( ),sendto ( ),sendto ( ),recvfrom
19、( ),Bind ( ),Socket ( ),recvfrom ( ),close ( ),暫停直到收到客戶端的資料包,資料 (請求),資料 (回應),處理請求,UDP伺服端,慣用埠,2018/8/11,41,UDP socket所使用的基本函式,由於TCP與UDP這兩個傳輸層本身的差異: UDP是非連線式、不可靠的資料包協定 TCP為連線導向式、可靠的位元組串流 因此使用TCP與使用UDP所撰寫的應用程式之間,有些基本的差異 UDP並不會建立與伺服端的連線,而只是使用sendto函式將資料包傳送給伺服端:這函式只需目的位址為參數 而伺服端也不接受來自客戶端的連線,而是呼叫recvfrom函
20、式,等待資料由客戶端送達,並傳回客戶端的協定位址和資料包,使伺服端傳送回應給正確客戶端。,2018/8/11,42,revfrom與sendto 函式,這兩個函式類似標準的read與write函式 #include ssize_t recvfrom (int sockfd, void *buff, size_t nbytes, int flags, struct sockaddr *from, socklen_t *addrlen) ; ssize_t sendto (int sockfd, const void *buff, size_t nbytes, int flags, const s
21、truct sockaddr *to, socklen_t addlen) ; 前三個參數sockfd、buff、nbytes與read及write的前三個參數相同,分別是描述子、指向讀取或寫入緩衝區的指標以及讀取或寫入的位元組收數目。 sendto 的to參數是socket位址結構,指定資料所要送往的協定位址, addrlen則是指定這個socket位址結構的長度,2018/8/11,43,revfrom與sendto 函式 (cont.),recvfrom函式會將傳送端的協定位址填入form所指用的socket位址結構,儲存在該socket位址結構中的位元組數目則會透過addrlen所指向
22、的整數,傳回給呼叫者。 recvfrom的最後二個參數類似accept的最後二個參數:在返回時,socket位址結構的內容會說明誰傳送這個資料包(UDP時)、或是誰啟始這個連線(TCP時)。 Sendto的最後二個參數則類似connect的最後二個參數:我們所填入的socket位址結構是資料包要送達的協定位址(UDP時),或是要與誰建立這個連線(TCP時)。,2018/8/11,44,UDP的客戶端伺服端範例,我們將使用UDP的方式來改寫TCP的echo範例。,UDP用戶端,UDP伺服端,sendto,recvfrom,recvfrom,sendto,fputs,stdin,stdout,fg
23、ets,2018/8/11,45,UDP Echo伺服端:main函式,#include “unp.h“int main(int argc, char *argv) int sockfd;struct sockaddr_in servaddr, cliaddr;sockfd = Socket(AF_INET, SOCK_DGRAM, 0);bzero(,2018/8/11,46,UDP Echo伺服端:main函式 (cont.),Bind(sockfd, (SA *) ,2018/8/11,47,UDP Echo伺服端:dg_echo函式,#include “unp.h“void dg_ec
24、ho(int sockfd, SA *pcliaddr, socklen_t clilen) int n;socklen_t len;char mesgMAXLINE;for ( ; ; ) len = clilen;n = Recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, ,2018/8/11,48,UDP Echo客戶端:main函式,#include “unp.h“int main(int argc, char *argv) int sockfd;struct sockaddr_in servaddr;if (argc != 2)err_quit(
25、“usage: udpcli “);bzero(,2018/8/11,49,UDP Echo客戶端:main函式 (cont.),sockfd = Socket(AF_INET, SOCK_DGRAM, 0);dg_cli(stdin, sockfd, (SA *) ,2018/8/11,50,UDP Echo客戶端:dg_cli函式,#include “unp.h“void dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen) int n;char sendlineMAXLINE, recvlineMAXLI
26、NE + 1;while (fgets(sendline, MAXLINE, fp) != NULL) sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);recvlinen = 0; /* null terminate */fputs(recvline, stdout); ,2018/8/11,51,TCP客戶與伺服端的運作流程圖,TCP伺服端,2018/8/11,52,UDP客戶與伺服端的運作流程,UDP客戶端,socket ( ),sendto ( ),sendto ( ),recvfrom ( ),Bind ( ),Socket ( ),recvfrom ( ),close ( ),暫停直到收到客戶端的資料包,資料 (請求),資料 (回應),處理請求,UDP伺服端,慣用埠,2018/8/11,53,WinSock References,Example Source Code http:/ Winsock Programmers FAQ http:/ Beginning Winsock Programming http:/