Linux Socket學習--域和地址族


先來說說無名套接口吧:

       套接口不一定需要地址,比如函數socketpair就生成了一對相互連接但是沒有地址的套接口,這就是所謂的無名套接口。

       有時候也會有這樣的情況,在相互連接的兩個太接口中有一個套接口不需要地址,例如當連接到一個遠程的套接口的時候,雖然必須確定遠程套接口的地址,但是發出調用的本地套接口卻可以是匿名的。

        有時候雖然需要一個地址進行通信,但是並不關心這個地址具體是什么,這個本地地址僅僅在通信過程中保持有效。如果給他分配一個固定的地址,浪費資源也加重了網絡管理的負擔,一次地址僅僅在使用的時候才產生。

     

       在一般情況下protocol取值為0,這個使得操作系統能夠選擇適合所選的domain的正確的缺省協議,當然這條規則也有例外,但是不在我們的討論之列。

       在上一篇文章中,我們說過AF_LOCAL和AF_UNIX是一樣的。下面我們來解釋一下:AF_LOCAL中的AF這個前綴表示地址族(address family),domain參數的意思就是在選擇到底使用哪個地址族。地址族的作用就是指明使用哪一種地址類型AF_LOCAL表示使用本地地址規則來生成地址,而AF_INET表示使用IP地址規則來生成地址。下面我們來看看通用套接口地址:

 

 

#include <sys.socket.h>

struct sockaddr
{
	sa_family_t sa_family;
	char        sa_data[14];
};

其中sa_family_t是一個無符號短整數,2個字節,整個數據結構的長度為16個字節。

對應於AF_LOCAL(AF_UNIX)的地址的結構名稱是sockaddr_un,具體內容如下:

#include <sys.un.h>
struct sockaddr_un
{
	sa_family_t sun_family;
	char        sun_path[108];
};

一些編程者在編寫地址內容的時候之前,習慣將結構中所有的字節都清零。這個可以通過調用函數memset來完成:

struct sockaddr_un uaddr;
memset(&uaddr, 0 , sizeof(uaddr))

下面我們來展示一個例子吧:

---------UNDOWN(此處代碼稍后添加)

下面我們來說說生成抽象本地地址:

傳統的AF_UNIX有一個缺陷,總是有一個文件系統對象生成,這個沒有必要也不方便,如果不刪除這個文件系統對象,而在調用bind的時候使用同樣的名字,就會發生錯誤。

在Linux內核2.2中,可以對本地套接口生成抽象地址,從而避免生成文件系統對象,這個實現很簡單,只需要把路徑名的第一個字節設置為空字節,而空字節后的其他部分就是抽象名。例子如下:

---------UNDOWN(此處代碼稍后添加)

下面來說說生成Internet套接口地址吧

在Linux中,使用最普遍的地址族就是AF_INET了,具有IPv4套接口地址的套接口可以和TCP/IP上的其他主機進行通信。結構如下:

#include <netinet/in.h>
struct sockaddr_in
{
	sa_family_t sin_family;
	uint16_t sin_port;
	struct in_addr sin_addr;
	unsigned char sin_zero[8];
};

struct in_addr{
	uint32_t s_addr;
}

下面我們簡要的介紹一下網絡字節序:

對於多字節數據,不同的cpu有不同的組織方式,其中最基本的兩種字節序為小端字節序和大端字節序。

小端字節序:是一種將低序字節存儲在起始位置的方法。

大端字節序:是一種將高序字節存儲在其實位置的方法。

我們可以使用一些函數來簡化大端/小端字節序的轉化工作,轉化的方向有2個:

1.主機字節序到網絡字節序

2.網絡字節序到主機字節序

下面是一些轉換函數:

#include <netinet/in.h>

unsigned long htonl(unsigned long hostlong);
unsigned long htons(unsigned short hostsgort);
unsigned long ntohl(unsigned long netlong);
unsigned short ntohl(unsigned short netshort);

      下面我們就准備生成一個統配的internet地址,之所以要生成統配地址,是因為有的主機安裝了多個網卡,每個網卡有獨立的ip地址,而且Linux容許每一個網卡指定不同的ip地址,這個時候,如果我們指定統配地址,那么系統就會自動選擇一條通往遠程服務的路由,當連接建立的時候,內核最終將決定使用哪一個本地的套接口地址。

      當想讓內核自動分配本地端口號的時候,也可以使用統配的端口號,要實現這一點很簡單,只需要將sinp_port的值設置為0.

下面的代碼展示了如何初始化一個具有統配IP地址和統配端口號的AF_INET地址:

struct sockaddr_in addr_inet;
int adr_len;

memset(&addr_inet,0,sizeof(addr_inet));

addr_inet.sin_family=AF_INET;
addr_inet.sin_port=ntohs(0);
addr_inet.sin_addr.a_addr=ntohl(INADDR_ANY);
adr_len=sizeof(addr_inet); 

另外一個普遍使用的ip地址是127.0.0.1,這個是一個回送設備,通過這個地址,我們的進程就可以與同一台主機上的其他進程進行通信。現在們只需要注意這個地址是怎么分配的:

addr_inet.sin_addr.a_addr=ntohl(INADDR_LOOPBACK);

下面我們來看一個例子:初始化一個特定的Internet地址:

---------UNDOWN(此處代碼稍后添加)

下面我們來看看生成X.25地址:

套接口界面容許編程者使用Linux支持的其他一些協議進行編程,X.25生成的地址和他非常的類似,他的結構如下:

#include <linux/x25.h>

struct sockaddr_x25{
	sa_familt_t sx25_addr[16];
	x25_address sx25_addr;
};

typedef struct{
	char x25_addr[16];
}x25_address;

下面的這個例子展示了如何使用X25:

---------UNDOWN(此處代碼稍后添加)

 

本文章並不打算對於Linux支持的所有的地址族內容進行介紹,實際上Linux所支持的協議也在增長中,所以此處簡要的介紹一下,感興趣的朋友可以自行搜索先關文獻。

除了IPv4之外,Linux至少還支持一下三類地址族協議:

AF_INET6-------------IPv6

AF_AX25--------------業余無線電X.25協議

AF_APPLETALK-----------Linux下AppleTalk協議的實現。

如果你想使用這些協議進行編程,那么在編譯內核的時候一定要選中相應的協議,請編程者注意,有些協議並沒有完全實現,而非完全實現或者實驗性的協議是不健壯的,有時候設置會導致整個系統奔潰。

在本文的最后,我們簡要的了解一下AF_UNSPEC地址族。

宏AF_UNSPEC代表不確定的地址族,當程序工作於不同的協議和地址族的時候,我們需要一種手段來達到整個目的,例如下面的代碼表示的是一個具有不同地址族的聯合:

union{
	sockaddr sa;
	sockaddr_un un;
	sockaddr_in in;
	sockaddr_in6 in6;
}u;

在對她進行賦值之前,我們需要把這個聯合初始化為:

u.sa_family=AF_UNSPEC;

以后在程序中,如果我們使用地址族AF_INET,則可以再次賦值:

u。sa_family=AF_INET;

所以說AF_UNSPEC是一個安全的占位符。當還不確定具體的地址族之前,我們可以使用他。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM