以下源码都在这几个源文件中
#include <sys/socket.h> // 通用socket地址存放的地方
#include <linux/in.h> // ipv4版本的socket地址存放的地方
#include <linux/in6.h> // ipv6版本的socket地址存放的地方
#include <linux/un.h> // unix版本的socket地址存放的地方
socket的通用地址
struct socketaddr{
sa_family_t sa_Family; /** 指明socket所属的协议族类型,主要有3种
* 地址族:AF_UNIX、 AF_INET、 AF_INET6
* 协议族:PF_UNIX、 PF_INET、 PF_INET6
* 描述 :UNIX本地域协议族、 TCP/IPv4协议族、 TCP/IPv6协议族
* 他们3个的对应的地址族和协议族的值都是相等的,因此都是可以互换着用的
*/
char sa_data[14]; /** 用于存放socket地址值,地址的长度也和协议族有关系
* PF_UNIX:文件的路径名,长度可达108字节
* PF_INET:16bit端口号和32bitIPv4地址,共6字节
* PF_INET6: 16bit的端口号,32bit流标识,128bitIpv6地址,32bit范围ID,共26字节
* 因此这里只有14字节的长度是不够使用的,后来使用下面那种
*/
};
/**
* 5.1.2 新的通用socket地址
*/
struct socketaddr_storage{
sa_family_t sa_family;
unsigned long int __ss_align;
char __ss_padding[128-sizeof(__ss_align)]; // 存放socket地址,总共120字节
// 3种协议的地址值都可以存放,这里和源码不太一样,想要对齐128还需要减去sa_family的大小,最后应为118,最后数组大小应该为
// char __ss_padding[128-sizeof(__ss_align)-sizeof(sa_family_t)]
};
我们去看源代码
// 在socket.h中
// 下面这个sockaddr和上面的socketaddr是大致是一样的
struct sockaddr
{
__SOCKADDR_COMMON (sa_); /* Common data: address family and length. */
char sa_data[14]; /* Address data. */
};
// 前往查看__SOCKADDR_COMMON,本质上是sa_family_t的别名,在预处理时会替换回去
#define __SOCKADDR_COMMON(sa_prefix) \
sa_family_t sa_prefix##family
// 前往查看sa_family_t,本质上是unsigned short int的别名,用数字代表某些地址族,和协议族相对应,在上面展示了主要是用的地址族和他们对应的协议族
typedef unsigned short int sa_family_t;
// 看第二个对应的socket通用类型的源码,
struct sockaddr_storage
{
__SOCKADDR_COMMON (ss_); /* Address family, etc. */
char __ss_padding[_SS_PADSIZE];
__ss_aligntype __ss_align; /* Force desired alignment. */
};
// 第一个成员的和上面一样
// 第二个成员是一个char数组,大小为_SS_PADSIZE
#define _SS_PADSIZE \
(_SS_SIZE - __SOCKADDR_COMMON_SIZE - sizeof (__ss_aligntype))
// 这3个都是别名,在预处理时会替换,我的机器上数组大小为120,
#define _SS_SIZE 128
#define __SOCKADDR_COMMON_SIZE (sizeof (unsigned short int))
#define __ss_aligntype unsigned long int
专用socket地址
所有专用socket地址类型变量在实际使用时都需要转化为通用的socket地址类型sockaddr, 因为所有socket编程接口都是使用的地址参数的类型都是sockaddr。
因此需要都小于118字节。
- IPv4协议族的专用socket地址
struct sockaddr_in {
__kernel_sa_family_t sin_family; /* Address family */
__be16 sin_port; /* Port number */
struct in_addr sin_addr; /* Internet address */
/* Pad to size of `struct sockaddr'. */
unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) -
sizeof(unsigned short int) - sizeof(struct in_addr)];
};
// 第一个就不多说
// 第二个参数是端口也就是unsigned short,为两个字节,16bit,对应tcp/ip报头的端口所占位数
typedef __u16 __bitwise __be16;
typedef unsigned short __u16;
// 第三个成员是ip地址,他是一个结构体,里面包含一个32位的unsigned int类型的成员,共4字节
struct in_addr {
__be32 s_addr;
};
typedef __u32 __bitwise __be32;
typedef unsigned int __u32;
// 第四个成员是用来填充的,因为网络上都是用的通用socket,到解构时才根据对应的协议的专用socket进行解析具体信息,
// 因此需要专用的socket长度和通用相等,使得他们能相互转换,等到使用时在转换回来就行,因此这里需要将整个结构体填充成16字节,这里对应的是第一种通用结构体,128太大了浪费内存
#define __SOCK_SIZE__ 16
- IPv6协议族的专用socket地址
// 总计大小为2+2+4+16+4=28字节
struct sockaddr_in6 {
unsigned short int sin6_family; /* AF_INET6 */
__be16 sin6_port; /* Transport layer port # */
__be32 sin6_flowinfo; /* IPv6 flow information */
struct in6_addr sin6_addr; /* IPv6 address */
__u32 sin6_scope_id; /* scope id (new in RFC2553) */
};
// 第一个成员类型:unsigned short int 大小为2字节,共16bit
// 第二个成员类型:unsigned short 大小为2字节,共16bit,符合报文中的首部的端口号大小格式
typedef __u16 __bitwise __be16;
typedef unsigned short __u16;
// 第三个成员类型: unsigned int 大小为4个字节,共32bit,这里应该是流标号,书上为20bit,这里用32bit,以实际为准
typedef __u32 __bitwise __be32;
typedef unsigned int __u32;
// 第四个成员为ipv6地址大小为128bit,也就是16字节
// 下面是一个union,每时每刻union中只有一个成员有值,这些成员的大小都是128bit因此union大小为128bit也就是16字节
struct in6_addr {
union {
__u8 u6_addr8[16];
#if __UAPI_DEF_IN6_ADDR_ALT
__be16 u6_addr16[8];
__be32 u6_addr32[4];
#endif
} in6_u;
typedef unsigned char __u8;
typedef __u16 __bitwise __be16;
typedef unsigned short __u16;
typedef __u32 __bitwise __be32;
typedef unsigned int __u32;
// 第四个成员是范围ID,大小为32bit,共4字节,类型为unsigned int
typedef unsigned int __u32;
- UNIX协议族的专用socket地址,进程间通信的一种方式是使用UNIX套接字,人们在使用这种方式时往往用的不是网络套接字,而是一种称为本地套接字的方式。这样做可以避免为黑客留下后门。
// 很简单,通过上面那些例子这个就很容易看懂了
struct sockaddr_un {
__kernel_sa_family_t sun_family; /* AF_UNIX */
char sun_path[UNIX_PATH_MAX]; /* pathname */
};
#define UNIX_PATH_MAX 108