先来说说无名套接口吧:
套接口不一定需要地址,比如函数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是一个安全的占位符。当还不确定具体的地址族之前,我们可以使用他。
==============================================================================