Top Banner
Socket 使使 Win32 API
35

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

Dec 20, 2015

Download

Documents

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
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. 中斷法