sockaddr、sockaddr_un、sockaddr_in、sockaddr_in6、struct in_addr、struct in6_addr的区别与使用

sock_addr


/* Linux下定义在usr/include/bits/socket.h中 */
/* Structure describing a generic socket address. */
struct sockaddr
{
	uint16_t sa_family; /* Comm data: address family and length. */
	char sa_data[14]; /* Address data. */
};

在socket套接字编程中,sockaddr是一个通用的结构体,可以存储不同类型的地址结构。sa_family表示地址族,AF_INET表示IPv4,AF_INET6表示IPv6,sa_data包含套接字中的目标地址和端口信息。但是这个结构体通常只用来提供统一接口可以被bind()、connect()等函数调用,而不直接对结构体操作。


sockaddr_un


/* Linux下定义在usr/include/sys/un.h中 */
/* Structure describing the address of an AF_LOCAL (aka AF_UNIX) socket. */
struct sockaddr_un
{
	uint16_t sun_family;
	char sun_path[108]; /* Path name. */
};

sockaddr_un是一种UNIX套接字,通常在使用这种方式时不用网络套接字,而是用本地套接字,这种方式可以避免为黑客留下后门(据说~)。本地套接字与网络套接字的使用大体相同,主要区别在于使用socket()创建时,域参数只能选择PF_LOCAL和PF_UNIX,通讯类型只能选择SOCK_STREAM和SOCK_DGRAM,协议为默认协议;bind()绑定时填充的是sockaddr_un结构体,它的sun_family参数只能选择AF_LOCAL和AF_UNIX,sun_path参数为本地文件路径,通常放在/temp目录下。


sockaddr_in


/* Linux下定义在usr/include/netinet/in.h中 */
/* Structure describing an Internet socket address. */
struct sockaddr_in
{
	uint16_t sin_family;
	uint16_t sin_port;			/* Port number. */
	struct in_addr sin_addr;	/* Internet address. */

	/* Pad to size of 'struct sockaddr'. */
	unsigned char sin_zero[sizeof (struct sockaddr) -
						   sizeof (uint16_t) - 
						   sizeof (uint16_t) -
						   sizeof (struct in_addr)];
	/* 其实就是unsigned char sin_zero[8]; */
};

sockaddr_in结构体是和sockaddr结构并列且等价的结构体,因此它们二者之间可以互相转化,也是真正用来提供给程序员进行填充操作的结构体,区别在于sockaddr_in将sa_data划分为sin_port和sin_addr,也就是把端口和IP地址信息区分开,sin_port采用了网络字节序,同时为了保持和sockaddr相同的字节大小,填充了8字节的sin_zero。这也是一个只针对IPv4地址的结构体,因此它的sin_family只能是AF_INET。


sockaddr_in6


/* Linux下跟sockaddr_in在同一个头文件 */
/* Ditto, for IPv6. */
struct sockaddr_in6
{
	uint16_t sin6_family;
	uint16_t sin6_port;			/* Transport layer port # */
	uint32_t sin6_flowinfo;		/* IPv6 flow information */
	struct in6_addr sin6_addr;	/* IPv6 address */
	uint32_t sin6_scope_id;		/* IPv6 scope-id */
};

sockaddr_in6也是一个专用的结构体,只针对IPv6,sin6_family参数只能选择AF_INET6,sin6_port也采用了网络字节序,sin6_flowinfo分为两个字段,低序的20位表示流标(flow label),高序的12位保留,对于具备范围的地址(scoped address),sin6_scope_id标识了其范围(scope)。


struct in_addr


/* Linux下与sockaddr_in在同一个头文件 */
/* Internet address. */
struct in_addr
{
	uint32_t s_addr;
};

这个结构体在sockaddr_in中被使用来存储IP地址信息,因此它通常不单独使用,而是与sockaddr_in结合一起使用,它的结构比较简单,就是采用了4字节存储IP地址,不过也采用了网络字节序进行存储,使用时需要注意转换。


struct in6_addr


/* Linux下与sockaddr_in在同一个头文件 */
/* IPv6 address */
struct in6_addr
{
	union
	{
		uint8_t __u6_addr8[16];
		uint16_t __u6_addr16[8];
		uint32_t __u6_addr32[4];
	}__in6_u;
#define s6_addr		__in6_u.__u6_addr8
#ifdef __USE_MISC
#define s6_addr16 	__in6_u.__u6_addr16
#define s6_addr32 	__in6_u.__u6_addr32
#endif
};

这个结构体也是与sockaddr_in6配合起来一起使用,通常不单独使用。它的结构比in_addr看起来稍微复杂,不过就是增加了一些预编译命令,它的主体是一个联合体,大小为16字节,因为IPv6地址长度是128位,刚好16字节,它使用联合体提供了几种不同的存储形式,为程序员提供了不同操作的可能。


  • 16
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值