1.1. 網路位元組序
記憶體中的多位元組資料相對於記憶體位址有大端和小端之分,磁碟檔案中的多位元組資料相對於檔案中的偏移位址也有大端小端之分。網路資料流同樣有大端小端之分,那麼如何定義網路資料流的位址呢?傳送主機通常將傳送緩衝區中的資料按記憶體位址從低到高的順序發出,接收主機把從網路上接到的位元組依次儲存在接收緩衝區中,也是按記憶體位址從低到高的順序儲存,因此,網路資料流的位址應這樣規定:先發出的資料是低位址,後發出的資料是高位址。
tcp/ip協議規定,網路資料流應採用大端位元組序,即低位址高位元組。例如上一節的udp段格式,位址0-1是16位的源埠號,如果這個埠號是1000(0x3e8),則位址0是0x03,位址1是0xe8,也就是先發0x03,再發0xe8,這16位在傳送主機的緩衝區中也應該是低位址存0x03,高位址存0xe8。但是,如果傳送主機是小端位元組序的,這16位被解釋成0xe803,而不是1000。因此,傳送主機把1000填到傳送緩衝區之前需要做位元組序的轉換。同樣地,接收主機如果是小端位元組序的,接到16位的源埠號也要做位元組序的轉換。如果主機是大端位元組序的,傳送和接收都不需要做轉換。同理,32位的ip位址也要考慮網路位元組序和主機位元組序的問題。
為使網路程式具有可移植性,使同樣的c**在大端和小端計算機上編譯後都能正常執行,可以呼叫以下庫函式做網路位元組序和主機位元組序的轉換。
#include uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
這些函式名很好記,h表示host,n表示network,l表示32位長整數,s表示16位短整數。例如htonl表示將32位的長整數從主機位元組序轉換為網路位元組序,例如將ip位址轉換後準備傳送。如果主機是小端位元組序,這些函式將引數做相應的大小端轉換然後返回,如果主機是大端位元組序,這些函式不做轉換,將引數原封不動地返回。
socket api是一層抽象的網路程式設計介面,適用於各種底層網路協議,如ipv4、ipv6,以及後面要講的unix domain socket。然而,各種網路協議的位址格式並不相同,如下圖所示:
ipv4和ipv6的位址格式定義在netinet/in.h
中,ipv4位址用sockaddr_in結構體表示,包括16位埠號和32位ip位址,ipv6位址用sockaddr_in6結構體表示,包括16位埠號、128位ip位址和一些控制字段。unix domain socket的位址格式定義在sys/un.h
中,用sockaddr_un結構體表示。各種socket位址結構體的開頭都是相同的,前16位表示整個結構體的長度(並不是所有unix的實現都有長度字段,如linux就沒有),後16位表示位址型別。ipv4、ipv6和unix domain socket的位址型別分別定義為常數af_inet、af_inet6、af_unix。這樣,只要取得某種sockaddr結構體的首位址,不需要知道具體是哪種型別的sockaddr結構體,就可以根據位址型別字段確定結構體中的內容。因此,socket api可以接受各種型別的sockaddr結構體指標做引數,例如bind、accept、connect等函式,這些函式的引數應該設計成void *型別以便接受各種型別的指標,但是sock api的實現早於ansi c標準化,那時還沒有void *型別,因此這些函式的引數都用struct sockaddr *型別表示,在傳遞引數之前要強制型別轉換一下,例如:
struct sockaddr_in servaddr;
/* initialize servaddr */
bind(listen_fd, (struct sockaddr *)&servaddr, sizeof(servaddr));
本節只介紹基於ipv4的socket網路程式設計,sockaddr_in中的成員struct in_addr sin_addr表示32位的ip位址。但是我們通常用點分十進位制的字串表示ip位址,以下函式可以在字串表示和in_addr表示之間轉換。
字串轉in_addr的函式:
#include int inet_aton(const char *strptr, struct in_addr *addrptr);
in_addr_t inet_addr(const char *strptr);
int inet_pton(int family, const char *strptr, void *addrptr);
in_addr轉字串的函式:
char *inet_ntoa(struct in_addr inaddr);
const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);
其中inet_pton和inet_ntop不僅可以轉換ipv4的in_addr,還可以轉換ipv6的in6_addr。 Java網路程式設計 基於TCP協議的網路程式設計(三)
增加聊天室功能 1.可以看到是誰發的訊息。2.實現私聊功能。實現方法 對於第乙個功能,可以使用map集合來儲存使用者資訊 第二個功能可以在客戶端傳送不同訊息時,對這些訊息進行處理,比如在訊息內容前後新增一些特殊字元,通過這些特殊字元來判斷。實現 特殊字元類 public inte ce chatro...
QT基於tcp協議網路程式設計
基於qt網路程式設計 基於tcp協議 c s模式程式設計 所需要的類 qtcpserver qtcpsocket 利用qt基於tcp協議編寫c s模式程式 兩個類中的訊號 qtcpserver newconnection qtcpsocket readyread connected disconne...
基於tcp的網路程式設計協議分析
在本地電腦的虛擬機器上搭建乙個tcp伺服器,如下 include include include include include include include include define buffer size 128 int main int argc,char ar if argc 3 if...