socket 基礎知識
概述
socket 是 TCP/IP 協定的最流行的一種網絡程式設計接口。它與 TCP/IP 一起最早實作于 4.1BSD UNIX 系統中,主要用于傳送級( TCP,UDP )程式設計。
socket 往往稱為套接口,套接口用于網絡中兩個通信實體間的通信,兩個實體可以存在于同一機器的不同程序中或不同機器的程序中。
套接口就好像 UNIX 中 pipe (管道),通信雙方程序通過它來與對方發送或接受資料。如同 pipe 用檔案描述字表示一樣,socket 也用檔案描述字表示,也稱為套接口描述字,或簡稱套接字。在網絡程式設計時要用套接字表示通信的對方。但兩者不同的是, pipe 的通信雙方在一台機器上,共用一個 pipe ,雙方使用不同的檔案描述字;而 socket 通信雙方一般在不同機器上,因而通信雙方均有一 socket 和對應的套接字負責通信,當然他們之間必須連接配接起來。
網絡中每個通信實體的 socket 是用一個三元組辨別的。三元組指的是:協定族(位址族),網絡位址、和傳輸層端口 (本文目前隻介紹 Ipv4 )。通信雙方的一個連接配接是用網絡五元組來辨別的,它是由雙方相同協定族的兩個本地三元組合成的。網絡五元組指的是:協定族(位址族)、本地網絡位址、本地端口、遠端網絡位址和遠端端口。 上述五元組往往稱為全相關。而三元組往往稱為半相關
套接口分為若幹類型,常用的是 SOCK_STREAM 和 SOCK_DGRAM 。 SOCK_STREAM 是面向連接配接的套接字,使用的協定是 TCP ,通信的雙方通過三次握手建立起虛拟的連接配接線路,通信的過程是可靠的。而 SOCK_DGRAM 是面向非連接配接的套接字,使用的協定是 UDP ,通信雙方以資料包的方式進行通信,通信的可靠性就不能得到保證。本項目要求采用 SOCK_STREAM 類型。
客戶機 / 伺服器計算模式
在 TCP/IP 網絡應用中 , 通信雙方互相作用采用客戶 / 伺服器模式 , 即用戶端向伺服器送出請求 , 伺服器接收到請求後提供相應的服務。一種常見的面向連接配接的運作方式如下:
伺服器方(首先啟動):
1. 打開一通信通道并告知本地主機,它願意在某一公認位址端口上 ( 周知口,如 http 為 80) 接受客戶請求。
2. 等待客戶請求到達該端口。
3. 接收并處理該請求,發送處理結果。如果是并發伺服器,則要建立( fork )一新的子程序來處理這個客戶請求。服務完成後,關閉這個新程序與客戶的通信連接配接,并終止該程序。
4. 傳回第二步,等待下一個客戶請求。
客戶方 :
1. 打開一通信通道,并連接配接到伺服器所在主機的特定端口。
2 .如伺服器接受了這個連接配接,則向它發出服務請求封包,等待并接收應答;
3. 請求結束後關閉通信通道。
從上面的運作過程可知:
1 .客戶與伺服器程序的作用是非對稱的。
2. 服務程序一般是先于客戶請求啟動的。隻要系統運作,該程序一直存在,直到正常終止或者強迫終止。
五元組格式(協定,本地 IP ,本地端口,遠方 IP ,遠方端口)的建立過程
伺服器一般都有兩個功能:監聽 和 處理
在監聽的時候,協定 / 本地 IP/ 本地端口(監聽端口)都是确定的,當收到用戶端的封包時,遠方 IP 就是封包的源 IP 位址,遠方端口就是封包的源端口,這樣一來五元組就确定了。
然後伺服器進入處理階段,需要開啟一個新的線程與用戶端互動,當然就需要确定一個新的五元組,這時候協定 / 本地 IP/ 遠方IP/ 遠方端口都來自監聽階段确定的五元組,而本地端口會在 1024 以上随機選取 (不再使用監聽端口,以便監聽其他用戶端的請求)。
用戶端的話正好相反,在發送請求時采用随機的本地端口 ,而接受響應時采用伺服器的源端口作為遠方端口。
系統調用
1. 建立套接字
#include <sys/types.h>;
#include <sys/socket.h>;
int socket(int family, int type, int protocol);
這是進行套接字通信的第一步,就是建立套接口。參數 family 表示所使用的協定族。參數 type 可以是 SOCK_STREAM 或SOCK_DGRAM 。 SOCK_STREAM 是指面向連接配接的通信,而 SOCK_DGRAM 是面向非連接配接的資料報方式。參數 protocol 描述的是協定種類,一般設為 0 。
Socket 函數用于建立三元組中的協定族部分 。
此系統調用如果成功就傳回的是套接字,以後的所有的對此套接口的操作都需引用這個描述字。如果調用失敗,就傳回 -1 ,并在全局變量 errno 儲存錯誤的類型。
2. 綁定套接字
int bind(int sockfd, cost struct sockaddr * saddr, socklen_t addrlen);
bind( ) 系統調用的作用是将由 socket( ) 所建立的套接字和位址結構 sockaddr 的一個執行個體相關聯,其中含有本地的資訊如 IP 位址、端口号。
bind 函數用于建立三元組中的本地 IP 位址和本地端口号部分。
參數 sockfd 是在此前用 socket 系統調用建立的套接字, sa 是指向結構 sockaddr 一個執行個體的指針。這個執行個體的類型一般是sockaddr_in ,在調用時需要進行強制轉換( struct sockaddr * ) &saddr (其中 saddr 是 sockaddr_in 類型)。參數addrlen 是結構 sockaddr 的大小即 sizeof ( struct sockaddr )。其中套接字的位址和端口可以在程式中指定,也可以由系統配置設定。
3. 監聽
int listen( int sockfd, int backlog ) ;
用 TCP 進行網絡通信,伺服器端要經曆幾個狀态,當調用 socket( ) 和 bind( ) 後,雖然套接字已經建立起來,但是其狀态是CLOSED 即關閉狀态。要進行通信就必須将套接字打開。對于伺服器端來說要被動打開,這就是 listen( ) 的功能。
下面就可以用 accept( ) 和 connect() 建立連接配接。這個過程其實就是 TCP 的“三次握手”。
4. 接受連接配接
int accept( int sockfd, struct sockaddr * client_addr, socklen_t *addrlen);
伺服器調用 accept( ) 來接受連接配接。當客戶與伺服器連接配接( connect )并且連接配接成功(三次握手)後 accept 則傳回另一個套接字。這個新建立的套接字稱為“連接配接套接字 ”。伺服器利用這個套接字來傳輸資料。而前面用 socket( ) 調用産生的套接字則稱之為“監聽套接字”,這個套接字專門監聽來自用戶端的請求。
參數 sockfd 是由 socket( ) 建立的連接配接套接字。 client_addr 是指向結構 sockaddr 的一個執行個體的指針,在傳回時用來存放請求連接配接的用戶端的 IP 位址、端口資訊。參數 addrlen 存放結構 * client_addr 的大小。
access 完成後通信雙方兩個三元組組成的五元組就建立起來了。
5. 連接配接伺服器
int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);
用戶端使用這個系統調用來連接配接目的主機(伺服器)的指定端口,以便和目的主機 ( 在 access 中等待 ) 進行通信。
sockfd 是客戶機的系統調用 socket() 傳回的套接字。 serv_addr 指向目的地 ( 伺服器)端口和 IP 位址的資料結構 struct sockaddr 。 addrlen 設定為 sizeof(struct sockaddr) 。
connect 完成後通信雙方兩個三元組組成的五元組就建立起來了。
本文轉自 zhenjing 部落格園部落格,原文連結: http://www.cnblogs.com/zhenjing/archive/2011/04/20/2021772.html ,如需轉載請自行聯系原作者