首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

Socket 位址結構深度解析:sockaddr、sockaddr_in 與網路位元組序

     編輯:關於C++

在 TCP/IP 網路程式設計中,Socket 位址結構是連線建立、資料收發的基石。本文系統整理 sockaddr 通用結構、sockaddr_in IPv4 專用結構、in_addr IP 位址封裝,並詳細說明網路位元組序與主機位元組序的轉換函數,幫助開發者建立清晰的記憶體佈局心智模型。

一、通用 Socket 位址結構 sockaddr

struct sockaddr {
    u_short sa_family;  // 位址族,如 AF_INET、AF_INET6、AF_UNIX
    char    sa_data[14]; // 14 位元組協議專用位址內容
};

sa_data 的具體解釋隨 sa_family 而異,長度固定 14 位元組僅為歷史妥協,實際 IPv4 只需 8 位元組,IPv6 需 28 位元組,Unix 域套接字甚至可達 110 位元組。因此 bind()、connect() 等 API 必須額外傳遞 socklen_t addrlen 參數明確指定結構長度。

二、IPv4 專用結構 sockaddr_in

struct in_addr {
    u_long s_addr; // 32 位元 IP 位址,網路位元組序
};

struct sockaddr_in {
    short         sin_family; // AF_INET
    u_short       sin_port;   // 16 位元埠號,網路位元組序
    struct in_addr sin_addr;  // 32 位元 IP 位址
    char          sin_zero[8]; // 填充對齊,保留未用
};

記憶體佈局共 16 位元組:sin_family(2) + sin_port(2) + sin_addr(4) + sin_zero(8)。實際使用時常以 sockaddr* 指標傳遞,靠 sa_family 辨識實際類型。

三、網路位元組序與轉換函數

網路位元組序(Big-Endian)為跨平台協議標準;主機位元組序視 CPU 架構而定(x86 為 Little-Endian)。四大轉換函數:

函數方向位元寬度典型用途
htons()Host → Network16-bit埠號 sin_port
htonl()Host → Network32-bitIP 位址 s_addr
ntohs()Network → Host16-bit解析收到的埠號
ntohl()Network → Host32-bit解析收到的 IP 位址

口訣:h=host、n=network、s=short(16)、l=long(32)。

四、常見錯誤與最佳實踐

  • 忘記轉換:直接將主機序整數賦值給 sin_port/s_addr,導致連線失敗或位址錯誤。
  • 結構未清零:sin_zero 未 memset(&addr, 0, sizeof(addr)),可能攜帶垃圾資料影響 bind。
  • 指標轉型:呼叫 bind(sock, (sockaddr*)&addr, sizeof(addr)) 時務必強制轉型,並傳遞正確長度。
  • 錯誤碼:bind 回傳 -1 時檢查 WSAGetLastError(),常見 WSAEADDRINUSE(埠被佔用)、WSAEINVAL(參數無效)。

五、IPv6 擴充:sockaddr_in6

struct sockaddr_in6 {
    u_short         sin6_family;   // AF_INET6
    u_short         sin6_port;     // 埠號
    u_long          sin6_flowinfo; // 流資訊
    struct in6_addr sin6_addr;     // 128 位元 IP
    u_long          sin6_scope_id; // 介面索引
};

現代程式建議使用 getaddrinfo() 統一解析域名/位址,自動填充 sockaddr_storage 以相容 IPv4/IPv6 雙棧。

六、總結

掌握 Socket 位址結構的記憶體佈局、位元組序轉換、長度參數用途,是編寫健壯網路程式的前提。建議封裝 AddrToString/StringToAddr 工具函數,統一處理轉換與格式化,減少手動填結構的錯誤機率。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved