1 / 35

Socket

Socket. 使用 Win32 API. 一個網路通訊程式. 什麼是 Socket. 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket ,是一個網路系統的通訊函式庫,在任何作 業系統中可以通用 主要的 5 大函式: socket()  電話 bind()  線路 ( 第幾分機 ?) listen()  準備好接聽 ( 啟用鈴聲 ) connect()  撥電話出去 accept()  對方接聽. Socket 函式,指定通訊協定. socket ( ) 函式. int SOCKET socket(

leda
Download Presentation

Socket

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Socket 使用Win32 API

  2. 一個網路通訊程式

  3. 什麼是Socket 凡是網路兩端互相連線傳送資料時的溝通介面就是 socket,是一個網路系統的通訊函式庫,在任何作 業系統中可以通用 主要的5大函式: socket()  電話 bind()  線路(第幾分機?) listen()  準備好接聽(啟用鈴聲) connect()  撥電話出去 accept()  對方接聽

  4. Socket函式,指定通訊協定

  5. socket ( )函式 int SOCKETsocket( intaf, inttype, intprotocol ); af:位址資料族系(family),用不同方式表示網路位址 type:通訊方式 Protocal:傳輸協定編號 回傳值:-1表示建立socket發生錯誤 若成功則回傳非負整數,稱為socket descriptor (socket描述子)

  6. 選項設定 af: 選擇AF_INET  Internet address family 對應的網路位址資料格式是 unsigned long(無號長整數) type:SOCK_STREAM 虛擬路徑連接方式(TCP用) SOCK_DGRAM 資料包方傳遞式(UDP用) protocal: 選擇IPPROTO_TCP (TCP通訊協定) 或寫入0,交由系統設定

  7. 範例 SOCKET sock; //宣告 sock = socket( //設定 AF_INET, SOCK_STREAM, IPPROTO_TCP );

  8. Bind函式,指定本地端位置

  9. Bind()函式 intbind( SOCKETs, const struct sockaddr*name, intnamelen ); s : 指定好通訊協定的socket name : 指定本地端位址,資料格式為sockaddr namelen : name之資料長度(單位byte) 回傳值:-1表錯誤,否則為0

  10. 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_INET sin_port:主機開啟的通訊埠號 用htons() 寫入 sin_addr:主機IP位址 in_addr資料格式 sin_zero[8]:目前沒用處,保留以後使用

  11. 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

  12. 範例 SOCKET Sock; sockaddr_in saServer; Sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); // 設定本機通訊用的位址 saServer.sin_family = AF_INET; saServer.sin_port = htons(5150); //啟用5150 port saServer.sin_addr.s_addr = inet_addr(“140.115.65.30”); //設定本機IP // 呼叫Bind函式 bind(Sock,(SOCKADDR*) &saServer, sizeof(saServer) );

  13. Listen函式 設定socket等待外部連線 listen()是使Socket進入等待連線狀態,等待客戶端(Client) 連上線來,很顯然的呼叫此函式的主機,功能會是一台伺服器(Server)。 如果有Client想要連過來,此時可以呼叫connect()來跟Server 連線。而Server接受後會建立新的socket和Client通訊,listen socket則繼續存在等待其他Client,直到關閉為止。

  14. listen()函式 intlisten( SOCKETs, intbacklog ); s:設定好bind(),並且尚未連線的socket Backlog:等待Server接受連線前,同時最大連線數 回傳值:-1表錯誤,否則為0

  15. Accept函式 接受外部連線 Blocking Non-blocking

  16. Accept() 函式 SOCKETaccept( SOCKETs, struct sockaddr*addr, int*addrlen ); s:一個設定為listen狀態的socket sddr:Client端位址資訊,由函式自動產生填入 addrlen:sddr長度,由函式自動產生 回傳值:-1表示錯誤,否則傳回另一個包含Client端資訊的新socket descriptor,作為傳送資料用 傳進accept()的listen socket本身並沒有辦法作資料的傳輸,所以必須透過accept()產生一個包含通訊協定、Server、Client資訊的新socket,利用他就可以進行資料的傳輸了

  17. 範例 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; }

  18. connect函式 與等待接聽的socket連線 Client端若要與Server溝通,必須透過connect建立連線,經過驗證確定連線成功後,才能進行資料傳輸。 三向交握(three-way handshake)機制: 1.Client向Server提出連線要求(connect()) 2.Server若接到要求,則回應Clinet接到要求 3.Client接到回應,向Server表示收到回覆 至此才算連線建立完成,雙方可以開始交換資料 若發生錯誤,則會由轉送中繼站回傳ICMP錯誤訊息 connect函式讀到後,會回報錯誤給程式

  19. connect()函式 intconnect( SOCKETs, const struct sockaddr*name, intnamelen ); 設定方式請參照bind()函式 name內資料為 回傳值:-1表錯誤,否則回傳0

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

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

  22. send()函式 intsend( SOCKETs, const char*buf, intlen, intflags ); s:一個建立連線成功的socket buf:用來儲存將送出資料的暫存器 len:buf的長度(byte) flags:選擇工作模式,一般填入0 回傳值:-1表錯誤,否則傳回送出資料的長度(byte)

  23. 範例 //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 ); }

  24. 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()是相同的

  25. closesocket() 與 shutdown()函式 intclosesocket( SOCKETs ); intshutdown( SOCKETs, inthow ); s:使用中的socket how:控制socket工作的方式 SD_RECEIVE 禁止輸入(disable recv()函式) SD_SEND 禁止輸出(disable send()函式) SD_BOTH 雙向禁止 回傳值:-1表錯誤,否則傳回0

  26. Server-Client Model recv() send()

  27. WINSOCKETS • #include <winsock2.h>

  28. WINSOCKETS • WSADATA wsadata; • if (WSAStartup(0x101,(LPWSADATA) &wsadata) != 0) { fprintf(stderr,"echo_srv: can't use WinSock DLL\n"); exit(1); }

  29. WINSOCKETS • WSACleanup();

  30. Server端用到的元件 • ListBox –顯示項目清單可以利用 ListBox1->Items->Add()新增資料或是ListBox1->Items->Insert()插入資料Add(字串), Insert(位置,字串)由於本次Server端只用到這一個元件,直接拉到滿版…

  31. Server端用到的元件 • Timer –計時器等待,定時輪詢

  32. Server端用到的語法 • #define A B 定義A為B,如利用#define Add(Text) ListBox1->Items->Insert(0,Text)這樣就可以用簡短的Add(“文字”)指令取代一長串的Insert指令 • 註:#define只會增加編譯時間(要轉換),對於程式的實際效能毫無影響

  33. Server端的工作流程 • 程式啟動直接開始監聽工作WSAStartupsocketbindlisten • 程式結束時關閉連線shutdownclosesocket

  34. Server端的工作流程 • 用Timer做定時監測若已經連線 { recv接收資料} 否則 { accept 接受連線} • !accept & recv 在沒有資料進入(沒人連線或沒有資料)時會阻塞住導致程式停止回應

  35. Server停止回應的處理方法 • 1. 用非阻塞式函數WSAAcceptExWSARecvWaitForSingleObject • 2. 多執行緒 • 3. 中斷法

More Related