libev這一類的。開始首先是萬物根源的協(xié)議信息
TCP/IP 協(xié)議了
TCP/IP 協(xié)議指的并不是一個協(xié)議,往往在生活中聽見的術(shù)語如:IP地址, TCP連接 等,總會被誤導(dǎo),以為就是一個東西TCP/IP說的是一個 協(xié)議族 ,也就是說是一堆協(xié)議的統(tǒng)稱| OSI | TCP/IP |
|---|---|
| 應(yīng)用層 表示層 會話層 | 應(yīng)用層 |
| 傳輸層 | 傳輸層 |
| 網(wǎng)絡(luò)層 | 網(wǎng)絡(luò)層 |
| 鏈路層 物理層 | 網(wǎng)絡(luò)接口層 |
IP地址 就是由它進(jìn)行封裝并傳往下一層*nix: 在 Terminal 中輸入 ifconfig -aWindows: 在 PowerShell 中輸入 ipconfig
*nix 和 Windows 都可以通過 ping <domain name> 命令進(jìn)行查詢一個完整的應(yīng)用程序傳輸數(shù)據(jù)時候 封裝 的過程(從右二向左依次封裝):
| 以太網(wǎng)首部 | IP | TCP/UDP | 真實數(shù)據(jù) | 尾部 |
|---|---|---|---|---|
| MAC地址 | IP地址 | TCP或者UDP協(xié)議 | 應(yīng)用程序數(shù)據(jù) | 效驗碼 |
| 源和目的MAC地址以及 | 及前層協(xié)議類型 | 源和目的端口號及前層應(yīng)用程序首部信息 | 應(yīng)用軟件信息和真正的數(shù)據(jù) |
其中端口號實際上就是 應(yīng)用程序的信息
接收數(shù)據(jù)時的 拆解 順序與 封裝 正好相反。
其中在傳輸過程中,作為接收方最開始使用的是 網(wǎng)絡(luò)接口層/數(shù)據(jù)鏈路層 的驅(qū)動程序(即操作系統(tǒng)自帶或另行安裝,總之不用使用的程序員寫就對了),來判斷這個包是否屬于我,判斷的依據(jù)就是 MAC地址,如果是再判斷什么協(xié)議
48bit 的, 前24bit由 IEEE 分配, 后24bit 由廠商分配。原則上是唯一的。MAC地址 和 IP地址
也許,許多大學(xué)計算機基礎(chǔ)課程,會講到 IP地址 有種類,分為 A,B,C...類,老師還介紹了各種類型的地址范圍。
但是在現(xiàn)代,這種分類早已經(jīng)失效,或者說正在逐漸消失,因為當(dāng)下的 IP 地址的 子網(wǎng)掩碼 可以是任意位,并以反斜杠跟在 IP地址后方。
比較現(xiàn)代的 IP地址 表示形式一般如此 1.185.223.1/24 代表著子網(wǎng)掩碼是由 24個 從左至右連續(xù)的的二進(jìn)制1 組合而成,其余位為0。稱為CIDR分類
事實上有一些實用且挺炫酷的函數(shù),可以先提一下
gethostbyname 用于域名查找 IP信息及各類信息
struct hostent * gethostbyname(const char * hostname)struct hostent 是存儲查找到的各類型信息,后方會有介紹hostname 即要查詢的域名gethostbyaddr 用于IP地址查找 域名及各類信息
struct hostent * gethostbyaddr(const char * addr, socklen_t len, int family)
addr 是要查詢的 IP地址,之所以是 const char * 是因為C語言歷史遺留的原因,實際上其類型應(yīng)為 struct in_addr *(IPv4)len 地址的長度,即 IPv4 為4, IPv6 為16family 即協(xié)議的種類, IPv4 為 AF_INET, IPv6 為 AF_INET6| struct hostent 的成員 | . | 類型 | . | 解釋 |
|---|---|---|---|---|
| h_name | char * | 官方名稱 | ||
| h_aliases | char ** | 域名集合,以NULL結(jié)尾 | ||
| h_addrtype | int | 地址族的類型 AF_INET 或 AF_INET6 | ||
| h_length | int | 地址的長度 4 或 16 | ||
| h_addr_list | char ** | IP的集合,以NULL結(jié)尾, 實際上每個元素的類型為 struct in_addr* |
實際上,這并不是一個好的方法,在后方將記錄 現(xiàn)代人的我們 該如何做到這些事情,以上只是以前的TCP/IP 編程
只適用于 IPv4
選擇使用 C 語言進(jìn)行編程
TCP 和 UDPPOSIX 標(biāo)準(zhǔn)->*nix平臺標(biāo)準(zhǔn) 和 Windows 平臺標(biāo)準(zhǔn)
對比兩種不同連接方式的不同地位的創(chuàng)建,使用
| TCP服務(wù)器 | TCP客戶端 | UDP服務(wù)器 | UDP客戶端 | 注釋 |
|---|---|---|---|---|
| socket() | socket() | socket() | socket() | 創(chuàng)建套接字 |
| bind() | bind() | bind() | 綁定所分配IP地址和端口號 | |
| listen() | connect() | 客戶端則綁定IP地址和端口號,并等待連接;服務(wù)器則是等待連接 | ||
| accept() | 服務(wù)器接受連接 | |||
| ... | ... | sendto/recvfrom() | sendto/recvfrom() | 對于UDP即是連接也是操作 |
| close() | close() | close() | close | 雙向直接關(guān)閉連接 |
| shutdown() | shutdown() | shutdown() | shutdown() | 可選擇方向的關(guān)閉連接,即更加靈活 |
如此對比雖然有一些小瑕疵,但是能夠大體上反映出真?zhèn)€網(wǎng)絡(luò)編程上不同方式的區(qū)別
注1: 對于 sendto recvfrom 這兩個接口函數(shù),并不一定是只能用在 UDP類型的 套接字上,同樣 TCP類型的 套接字也能使用,但是這么做并沒有什么意義。
注2: 實際上 UDP 沒有所謂的 服務(wù)器和和護短,因為本來就是單純的互相發(fā)來發(fā)去。客戶端端口 一般是隨機的
以上是 *nix平臺下的標(biāo)準(zhǔn), Windows下的操作方式和 API有細(xì)微不同,但大部分是一致的。
| Windows | *nix |
|---|---|
| socket() | socket() |
| bind() | bind() |
| connect() | connect() |
| listen() | listen() |
| accept() | accept() |
| closesocket() | close() |
| send() | send() |
| read() | read() |
| sendto() | sendto() |
| recvfrom() | recvfrom() |
不僅僅是接口名字相同,參數(shù)個數(shù)以及功能也是一致,即使有一個例外,其參數(shù)以及使用方法也相同。
那豈不是可以直接移植了?
并不!
在 Windows 套接字編程時 , 由于 Windows 將其實現(xiàn)為動態(tài)庫,所以在使用時需要將其加載進(jìn)程序。
故而多加了加載操作。
int WSAStartup(
WORD wVersionRequested,
LPWSADATA lpWSAData /* 這是一個結(jié)構(gòu)體, 傳入類型為WSADATA* */
);
int WSACleanup(void);
每當(dāng)在 Windows 上進(jìn)行套接字編程時,總要指定某個版本的套接字庫:
WSADATA wsaData;
int err_code;
/*
* MAKEWORD()的作用在于將版本號轉(zhuǎn)為指定格式傳入
* 當(dāng)下(2015-10)套接字庫的版本號最高是 2.2
*/
err_code = WSAStartup(MAKEWORD(2, 2), &wsaData);
/* TODO Something */
WSACleanup();
這是最基本的在 Windows 上使用 套接字 編程的流程,但是如果本平臺的套接字庫最高版本并不符合當(dāng)前要求呢?
那么首先會將套接字版本庫盡可能設(shè)置到平臺的 最高版本 ,可以通過結(jié)構(gòu)體 WSADATA 進(jìn)行查詢
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
printf("Could not find a usable version of Winsock.dll\n");
WSACleanup();
return 1;
}
總體而言,
Windows平臺和*uix平臺的區(qū)別在于,前者使用時需要 加載和清除 套接字庫 其余邏輯流程一致,畢竟只有統(tǒng)一才能越利于編程世界的發(fā)展。