Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket...

35
Socket 使使 Win32 API
  • date post

    20-Dec-2015
  • Category

    Documents

  • view

    222
  • download

    4

Transcript of Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket...

Page 1: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

Socket

使用 Win32 API

Page 2: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

一個網路通訊程式

Page 3: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

什麼是 Socket凡是網路兩端互相連線傳送資料時的溝通介面就是socket ,是一個網路系統的通訊函式庫,在任何作業系統中可以通用

主要的 5大函式:socket() 電話bind() 線路 (第幾分機 ?)listen() 準備好接聽 (啟用鈴

聲 )connect() 撥電話出去accept() 對方接聽

Page 4: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

Socket 函式,指定通訊協定

Page 5: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

socket ( ) 函式int SOCKET socket(

int af,int type, int protocol

);

af :位址資料族系 (family) ,用不同方式表示網路位址type :通訊方式Protocal :傳輸協定編號回傳值: -1表示建立 socket 發生錯誤

若成功則回傳非負整數,稱為 socket descriptor

(socket 描述子 )

Page 6: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

選項設定af: 選擇 AF_INET Internet address family

對應的網路位址資料格式是unsigned long( 無號長整數 )

type : SOCK_STREAM 虛擬路徑連接方式 (TCP 用 ) SOCK_DGRAM 資料包方傳遞式 (UDP 用 )

protocal : 選擇 IPPROTO_TCP (TCP 通訊協定 ) 或寫入 0,交由系統設定

Page 7: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

範例SOCKET sock; // 宣告

sock = socket( // 設定AF_INET, SOCK_STREAM, IPPROTO_TCP

);

Page 8: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

Bind 函式,指定本地端位置

Page 9: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

Bind() 函式int bind(SOCKET s, const struct sockaddr* name, int namelen

);

s : 指定好通訊協定的 socket name : 指定本地端位址,資料格式為 sockaddrnamelen : name 之資料長度 (單位 byte)回傳值: -1表錯誤,否則為 0

Page 10: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

Sockaddr_in 格式 (IPv4 用 )struct sockaddr_in {

short sin_family;u_short sin_port; struct in_addr sin_addr; char sin_zero[8];

};sin_family: 位址資料族系,同樣設定為 AF_INETsin_port: 主機開啟的通訊埠號 用 htons() 寫入sin_addr: 主機 IP 位址 in_addr 資料格式sin_zero[8]: 目前沒用處,保留以後使用

Page 11: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

in_addr 格式typedef struct in_addr {

union {struct {u_char s_b1,s_b2,s_b3,s_b4;} S_un_b;struct {u_short s_w1,s_w2;} S_un_w;u_long S_addr;

} S_un; } in_addr;

使用了 union 的結構體,實際上的大小是一個 32bit 的長整數所以只要注意 u_long S_addr 這個變數 將 IP 對此變數寫入便可

函式庫引入的標頭檔應該會有定義#define s_addr S_un.s_addr此後只要對前一頁之變數 sin_addr.s_addr 存取便可寫入時使用 inet_addr(“IP 位址字串” )轉換成 unsigned long

Page 12: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

範例SOCKET Sock; sockaddr_in saServer;

Sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP

);

// 設定本機通訊用的位址saServer.sin_family = AF_INET; saServer.sin_port = htons(5150); // 啟用 5150 portsaServer.sin_addr.s_addr = inet_addr(“140.115.65.30”); // 設定本機 IP

// 呼叫 Bind 函式 bind(Sock,(SOCKADDR*) &saServer, sizeof(saServer) );

Page 13: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

Listen 函式 設定 socket 等待外部連線

listen() 是使 Socket 進入等待連線狀態,等待客戶端 (Client) 連上線來,很顯然的呼叫此函式的主機,功能會是一台伺服器 (Server) 。

如果有 Client 想要連過來,此時可以呼叫 connect() 來跟 Server 連線。而 Server 接受後會建立新的 socket 和 Client 通訊, listen socket則繼續存在等待其他 Client ,直到關閉為止。

Page 14: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

listen() 函式int listen(

SOCKET s, int backlog

);

s :設定好 bind(), 並且尚未連線的 socketBacklog :等待 Server 接受連線前,同時最大連線數

回傳值: -1表錯誤,否則為 0

Page 15: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

Accept 函式 接受外部連線

Blocking Non-blocking

Page 16: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

Accept() 函式SOCKET accept(

SOCKET s, struct sockaddr* addr, int* addrlen

); s :一個設定為 listen 狀態的 socketsddr : Client 端位址資訊,由函式自動產生填入addrlen : sddr 長度,由函式自動產生回傳值: -1表示錯誤,否則傳回另一個包含 Client 端資訊的新 socket

descriptor ,作為傳送資料用

傳進 accept() 的 listen socket 本身並沒有辦法作資料的傳輸,所以必須透過 accept()產生一個包含通訊協定、 Server、 Client 資訊的新 socket ,利用他就可以進行資料的傳輸了

Page 17: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

範例ListenSocket 為一個 bind() 過且未連線的 socket

// 設定 socket 為接聽外部連線用if (listen( ListenSocket, 1 ) == SOCKET_ERROR) printf("Error listening on socket.\n");

// 宣告一個用來和 Client 連線用的 socket SOCKET AcceptSocket;

// 接受外部連線while(1) {

AcceptSocket = SOCKET_ERROR; // 尚未取得 socket descriptor ,等待外部連線進入時重設

while( AcceptSocket == SOCKET_ERROR ) { AcceptSocket = accept( ListenSocket, NULL, NULL );

} printf("Client connected.\n"); break;

}

Page 18: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

connect 函式 與等待接聽的 socket 連線

Client 端若要與 Server 溝通,必須透過 connect 建立連線,經過驗證確定連線成功後,才能進行資料傳輸。

三向交握 (three-way handshake) 機制:1.Client向 Server提出連線要求 (connect())2.Server 若接到要求,則回應 Clinet 接到要求3.Client 接到回應,向 Server 表示收到回覆至此才算連線建立完成,雙方可以開始交換資料若發生錯誤,則會由轉送中繼站回傳 ICMP 錯誤訊息connect 函式讀到後,會回報錯誤給程式

Page 19: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

connect() 函式int connect(

SOCKET s, const struct sockaddr* name, int namelen

);

設定方式請參照 bind() 函式name內資料為回傳值: -1表錯誤,否則回傳 0

Page 20: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

recv(),send() 函式 處理資料收送從先前設定好 Server與 Client 的通訊方式後,我們利用進行資料交換的函式 recv(),send() 來處理要溝通的資料,其實資料溝通的函式有許多種類, read(),write(),readv(),writev(),recvmsg(),sendmsg() 等等,我們介紹 recv() 和 send()給大家入門,其他函式的使用可以查閱MSDN 或 man 說明文件

Page 21: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

recv() 函式int recv(

SOCKET s, char* buf, int len, int flags

);

s :一個建立連線成功的 socketbuf :呼叫 recv ,用來儲存收到資料的暫存器len : buf 的長度 (byte)flags :選擇工作模式,一般填入 0回傳值: -1表錯誤,否則傳回接受到資料的長度 (byte)

Page 22: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

send() 函式int send(

SOCKET s, const char* buf, int len, int flags

);

s :一個建立連線成功的 socketbuf :用來儲存將送出資料的暫存器len : buf 的長度 (byte)flags :選擇工作模式,一般填入 0回傳值: -1表錯誤,否則傳回送出資料的長度 (byte)

Page 23: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

範例//Server 端int bytesSent; int bytesRecv = SOCKET_ERROR; char sendbuf[32] = "Server: Sending Data."; char recvbuf[32] = "";

bytesRecv = recv( m_socket, recvbuf, 32, 0 ); printf( "Bytes Recv: %ld\n", bytesRecv ); bytesSent = send( m_socket, sendbuf, strlen(sendbuf), 0 ); printf( "Bytes Sent: %ld\n", bytesSent );

//Client 端int bytesSent; int bytesRecv = SOCKET_ERROR; char sendbuf[32] = "Client: Sending data."; char recvbuf[32] = "";

bytesSent = send( m_socket, sendbuf, strlen(sendbuf), 0 ); printf( "Bytes Sent: %ld\n", bytesSent ); while( bytesRecv == SOCKET_ERROR ) {

bytesRecv = recv( m_socket, recvbuf, 32, 0 ); if ( bytesRecv == 0 || bytesRecv == WSAECONNRESET ) {

printf( "Connection Closed.\n"); break;

} if (bytesRecv < 0) return; printf( "Bytes Recv: %ld\n", bytesRecv );

}

Page 24: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

closesocket(),shutdown() 函式 中斷連線在 accept() 或 connect() 成功後建立的通訊用 socket ,必須由 Client 或 Server下達 closesocket() 或 shutdown() 來結束連線。

closesocket() 可以用來終止 TCP 連線,但不會馬上關閉,必須等到該 socket 不在動作後才切斷連線,這和 TCP 協定中使用到的 sliding window有關,這是用完再關的函式,而 shutdown() 是有強制性質的中斷連線函式,用來控制 socket 的 IO 。

一個好的中斷連線作法應有四步:1.結束傳送資料2.使用 shutdown() ,設定為禁止送出資料3.呼叫 recv() ,確定收到的資料長度為 0,避免遺漏資訊4.closesocket() 來關閉 socket

註:在 Winsock 中使用的 closesocket() 和 BSD socket 中的 close() 是相同的

Page 25: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

closesocket() 與 shutdown() 函式

int closesocket( SOCKET s

);

int shutdown( SOCKET s, int how

);

s :使用中的 socket how:控制 socket工作的方式

SD_RECEIVE 禁止輸入 (disable recv() 函式 )SD_SEND 禁止輸出 (disable send() 函式 )SD_BOTH 雙向禁止

回傳值: -1表錯誤,否則傳回 0

Page 26: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

Server-Client Model

recv() send()

Page 27: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

WINSOCKETS #include <winsock2.h>

Page 28: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

WINSOCKETS WSADATA wsadata;

if (WSAStartup(0x101,(LPWSADATA) &wsadata) != 0) {

fprintf(stderr,"echo_srv: can't use WinSock DLL\n"); exit(1); }

Page 29: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

WINSOCKETS WSACleanup();

Page 30: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

Server 端用到的元件 ListBox – 顯示項目清單

可以利用 ListBox1->Items->Add() 新增資料或是 ListBox1->Items->Insert() 插入資料

Add( 字串 ), Insert( 位置 , 字串 )

由於本次 Server 端只用到這一個元件,直接拉到滿版…

Page 31: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

Server 端用到的元件 Timer – 計時器

等待,定時輪詢

Page 32: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

Server 端用到的語法 #define A B 定義 A 為 B ,如利用

#define Add(Text) ListBox1->Items->Insert(0,Text)這樣就可以用簡短的 Add(“ 文字” ) 指令取代一長串的 Insert 指令

註: #define 只會增加編譯時間 ( 要轉換 ) ,對於程式的實際效能毫無影響

Page 33: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

Server 端的工作流程 程式啟動直接開始監聽工作

WSAStartupsocketbindlisten

程式結束時關閉連線shutdownclosesocket

Page 34: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

Server 端的工作流程 用 Timer 做定時監測

若已經連線 {recv 接收資料

} 否則 {accept 接受連線

}

! accept & recv 在沒有資料進入 ( 沒人連線或沒有資料 ) 時會阻塞住導致程式停止回應

Page 35: Socket 使用 Win32 API. 一個網路通訊程式 什麼是 Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作

Server 停止回應的處理方法 1. 用非阻塞式函數

WSAAcceptExWSARecvWaitForSingleObject

2. 多執行緒

3. 中斷法