《TCP/IP網絡編程》第3章 地址族與數據序列

3.1 分配給套接字的IP地址與端口號

    IP是InternetProtocol(網絡協議)的簡寫,是爲收發網絡數據而分配給計算機的值

    端口號並非賦予計算機的值,而是爲區分程序中創建的套接字而分配給套接字的序號

1.       網絡地址(Internet Address)

  • IPv4 4字節地址族
  • IPv6 16字節地址族

    IPv4標準的4字節IP地址分爲網絡地址和主機(指計算機)地址,且分爲A、B、C、D、E等類型。



    關注:路由器與交換機的作用

2.       用於區分套接字的端口號

    計算機中一般配有NIC(NetworkInterface Card,網絡接口卡)數據傳輸設備。

    通過NIC向計算機內部傳輸數據時會用到IP。操作系統負責把傳遞到內部的數據適當分配給套接字,這時就要利用端口號。

    端口號就是在同一操作系統內爲區分不同套接字而設置的,因此無法將1個端口號分配給不同套接字。

    另外,端口號由16位構成,可分配的端口號範圍是0~65535。但0~1023是知名端口(Well-Known  PORT),一般分配給特定應用程序。

    另外,雖然端口號不能重複,但TCP套接字和UDP套接字不會共用端口號,所以允許跨協議的端口號重複。

    總之,數據傳輸目標地址同時包含IP地址和端口號,只有這樣,數據纔會被傳輸到最終的目的應用程序(應用程序套接字)。

3.2 地址信息的表示

    應用程序中使用的IP地址和端口號以結構體的形式給出了定義。

1.       表示IPv4地址的結構體

struct sockaddr_in
{
    sa_family_t       sin_family;  // 地址族

    uint16_t          sin_port;     //16位TCP/IP端口號,網絡字節序

    struct in_addr    sin_addr;     // 32位IP地址,網絡字節序

    char              sin_zero[8];  // 不使用,僅爲使sockaddr_in與sockaddr結構體保持一致
};

struct  in_addr
{
    In_addr_t  s_addr;      // 32位IPv4地址
};

      

    如果使用int32_t類型的數據,就能保證在任何時候都佔用4字節,即使將來用64位表示int類型也是如此。

    sockaddr_in 結構體變量地址值將以如下方式傳遞給bind函數:

struct sockaddr
{
    sa_family_t       sin_family;       //  地址族
    char              sa_data[14];      // 地址信息
};

    此結構體成員sa_data保存的地址信息中需包含IP地址號和端口號,剩餘部分應填充0,這也是bind函數的要求。

    sockaddr_in是保存IPv4地址信息的結構體,而sockaddr並非只爲IPv4設計。所以仍需單獨指定sin_family。

3.3 網絡字節序與地址轉換

    代表CPU數據保存方式的主機字節序(HostByte Order)在不同CPU中也各不相同。在通過網絡傳輸數據時,約定:統一使用網絡字節序(NetworkByte Order),即大端字節序。

unsignedshort htons(unsigned short);
unsignedshort ntohs(unsigned short);
unsignedlong htonl(unsigned long);
unsignedlong ntohl(unsigned long);

    htons中的h代表主機(host)字節序;n代表網絡(network)字節序。

    s指的是short,l指的是long。(Linux中long類型佔用4個字節)

    通常,以s作爲後綴函數用於端口號轉換,以l作爲後綴函數用於IP地址轉換。

    問:數據傳輸過程中都需要轉換嗎?

    答:除了向sockaddr_in結構體變量填充數據外,其他情況無需考慮字節序問題。

3.4 網絡地址的初始化與分配

1.       將字符串信息轉換爲網絡字節序的整數型

    sockaddr_in中保存IP地址信息的成員爲32位整數型,因此,爲了分配IP地址,需要將點分十進制(DottedDecimal Notation)的IP地址化爲32位整數型數據。

#include<arpa/inet.h>
in_addr_t  inet_addr(const char *string); 
//成功時返回32位大端序整數型值,失敗時返回INADDR_NONE

    該函數將字符串形式的IP地址轉換成32位大端序(網絡序)整數型IP地址。還可檢測無效IP地址。 

#include<arpa/inet.h>
int  inet_aton(const  char * string,  struct in_addr *addr); 

    該函數與inet_addr函數功能相同,但其利用了in_addr結構體,使用頻率很高;與inet_aton作用相反的函數:

#include<arpa/inet.h>
char* inet_ntoa(struct  in_addr  addr);

注意:調用時應將字符串信息複製到其他內存空間。(通過strcpy函數)

2.       常用的網絡地址初始化方法

    atoi函數把字符串轉換成整型。

3.       INADDR_ANY

    每次創建服務器端套接字都要輸入IP地址會有些繁瑣,此時可如下初始化地址信息:

struct sockaddr_inaddr;
......
addr.sin_addr.s_addr= htonl(INADDR_ANY);

    若採用這種方式,則可自動獲取運行服務器端的計算機IP地址,不必親自輸入。而且,若同一計算機中已分配多個IP地址(多宿主(Multi-homed)計算機,一般路由器屬於這一類),則只要端口號一致,就可以從不同IP地址接收數據。(實際IP地址的個數與計算機中安裝的NIC的數量相等,若只有一個NIC,則直接使用INADDR_ANY)

    127.0.0.1是回送地址(loopback address),指的是計算機自身IP地址。若用實際IP地址代替此地址也能正常運轉。

4.       向套接字分配網絡地址

#include<sys/socket.h>
int bind(int sockfd, structsockaddr *myaddr, socklen_t addrlen);

-sockfd:要分配地址信息(IP地址和端口號)的套接字文件描述符;

-myaddr: 存有地址信息的結構體變量地址值;

-addrlen: 第二個結構體變量的長度;


發佈了28 篇原創文章 · 獲贊 2 · 訪問量 5156
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章