網絡中的進程是如何通訊的?html
在網絡中進程之間進行通訊的時候,那麼每一個通訊的進程必須知道它要和哪一個計算機上的哪一個進程通訊.不然通訊無從談起!在本地能夠經過進程PID來惟一標識一個進程,可是在網絡中這是行不通的.其實TCP/IP協議族已經幫咱們解決了這個問題,網絡層的「ip地址」能夠惟一標識網絡中的主機,而傳輸層的「協議+端口」能夠惟一標識主機中的應用程序(進程).這樣利用三元組(ip地址,協議,端口)就能夠標識網絡的進程了,網絡中的進程通訊就能夠利用這個標誌與其它進程進行交互.linux
什麼是套接字?數據庫
套接字是做爲4BDS UNIX的進程通訊機制,它用於描述 IP 地址和端口,是一個用於通訊鏈接的文件描述符.舉個例子來講.套接字就好像是銀行的服務窗口.而後每一個服務窗口上面都有一個標號(對應套接字的 IP 地址),而後銀行又有規定標號爲多少的窗口提供什麼服務,標號爲窗口提供什麼服務(窗口標號就相似套接字中記錄的 IP 地址,服務就相似着套接字的端口號),那麼客戶就能夠根據這個窗口標號去請求所須要的服務.編程
在 socket 中是怎麼作到對另外一個套接字鏈接的緩存
首先很明顯,上面一直在強調兩個進程在進行與網絡通訊的時候,兩個進程都必須知道對方是誰(經過"ip地址+端口"),不然就沒法進行通訊,能夠設想下你寫了封信給你的朋友小明,那麼你忘了寫寄信地址和寄信人.那麼你把這份信寄了.而後你就開始等待小明的回信,那麼小明就算收到信了也不知道這封信是誰寄的和該把回覆信寄給誰.那麼你能收到回信麼?安全
可是有時候你在寫通訊時候好比 tcp 的客戶端,你發現你沒有對套接字進行地址綁定也依舊能夠和服務器通訊,那這又是爲何?由於操做系統幫你作了這件事,操做系統在發現你沒有將一個套接字綁定到對應的 ip 地址和端口號而調用 listen 和connect 的時候.那麼它會自動給你分配 IP 地址和端口號.接着上面那個寄信的例子,假設你在寄信的時候是託給個朋友幫你寄.那麼這個好心的朋友發現了你犯的這個粗心的錯誤.那麼他便把在寄信人和寄信地址處填寫上了你的名字和你的地址,那麼小明就能夠和你正常通訊了.服務器
既然這爲何服務器還要大費周章的去對一個監聽端口進行地址綁定呢?咱們仍是用上面那個寄信的例子來講,假設你頗有錢,有三套房子(即服務器對應三個 IP),你依舊沒有寫寄信人和寄信地址.那麼你雖然託朋友給你寄,可是你這個朋友也不肯定你如今住那套房子裏,那麼他便把這個三個地址之中的一個地址填了上去.而偏偏很不幸的是你已近好久沒有住那套房子了.那麼小明即便回覆了你的信,你也可能收不到信了.因此服務器必需要對監聽套接字進行地址進行綁定!網絡
什麼是大小端架構
由於計算機內存是以字節(八位)爲單位來存儲東西的.那麼在存儲大於一字節的數據時候就會存在一個問題,按什麼樣的順序去存放這樣的數據,是低位字節排放在內存的低地址端仍是低位字節排放在內存的高地址端.然而這個每每和具體CPU架構有關,而非操做系統.那麼首先咱們來講明下大端模式和小端模式的區別:socket
這樣也許很差理解那麼舉個例子來講.若是將一個 16 位的整數 0x1234 存放到一個短整型變量(short)中,這個短整型變量採用大端或者小端模式在內存中的存儲由下表所示.
socket 中的 tcp 編程的大體流程
注意問題
地址結構體
struct in_addr{in_addr_t s_addr;}; struct sockaddr_in{ sa_family_t sin_family; in_port_t sin_port; struct in_addr sin_addr; };
struct in6_addr{ sa_family_t sin6_family; in_port_t sin6_port; uint32_t sin6_flowinfo; struct in6_addr sin6_addr; uint32_t sin6_scope_id; };
地址查詢
經過調用 gethostent 獲取主機信息,當 gethostent 返回時,獲得一個指向 hostent 結構體指針,該結構體可能包含一個靜態的數據緩存區,每次調用 gethostlent 將會覆蓋這個緩存區.返回的地址採用網絡字節序.相關函數:
相關結構體:
struct hostent{ char *h_name; char **h_aliases; char h_addrtype; char h_length; char **h_addr_list; ... };
將協議名字和協議號採用如下函數映射
相關函數
相關結構體
struct protoent{ char* p_name; char** p_aliases; int p_proto; }
服務查詢
服務是由地址的端口號部分表示的.每一個服務由惟一的熟知的端口號來提供,採用函數 getservbyname 能夠將一個服務名字映射到一個端口號,函數getservbyport將一個端口號映射到一個服務器名,或者採用函數 getservent順序掃描服務數據庫.相關函數:
struct servent{ char *s_name; char **s_aliases; int s_port; cjar *s_proto; };
套接字的經常使用 API
參考資料