我看功能,如connect()
和bind()
用C插座和发现,他们需要一个指向sockaddr
结构.我一直在阅读并使你的应用程序独立于AF,使用sockaddr_storage
结构指针并将其转换为sockaddr
指针是有用的,因为它具有更大的地址所需的额外空间.
我想知道的是,函数connect()
和bind()
请求sockaddr
指针的方法是如何从指针访问数据,指针指向比预期更大的结构.当然,你传递的是你提供它的结构的大小,但是函数用来从指向更大结构的指针获取IP地址的实际语法是struct *sockaddr
什么?
这可能是因为我来自OOP语言,但它似乎有点乱,有点乱.
the*_*ole 46
期望指针的函数struct sockaddr
可能在向它们sockaddr
发送指针时将你发送给它们的指针强制转换为struct sockaddr_storage
.通过这种方式,他们就像访问它一样访问它struct sockaddr
.
struct sockaddr_storage
设计适合a struct sockaddr_in
和struct sockaddr_in6
您不创建自己的struct sockaddr
,您通常创建一个struct sockaddr_in
或一个struct sockaddr_in6
取决于您正在使用的IP版本.为了避免试图知道您将使用的IP版本,您可以使用struct sockaddr_storage
哪个可以容纳.这将由struct sockaddr
connect(),bind()等函数进行类型转换,并以这种方式访问.
您可以在下面看到所有这些结构(填充是特定于实现的,用于对齐目的):
struct sockaddr {
unsigned short sa_family; // address family, AF_xxx
char sa_data[14]; // 14 bytes of protocol address
};
struct sockaddr_in {
short sin_family; // e.g. AF_INET, AF_INET6
unsigned short sin_port; // e.g. htons(3490)
struct in_addr sin_addr; // see struct in_addr, below
char sin_zero[8]; // zero this if you want to
};
struct sockaddr_in6 {
u_int16_t sin6_family; // address family, AF_INET6
u_int16_t sin6_port; // port number, Network Byte Order
u_int32_t sin6_flowinfo; // IPv6 flow information
struct in6_addr sin6_addr; // IPv6 address
u_int32_t sin6_scope_id; // Scope ID
};
struct sockaddr_storage {
sa_family_t ss_family; // address family
// all this is padding, implementation specific, ignore it:
char __ss_pad1[_SS_PAD1SIZE];
int64_t __ss_align;
char __ss_pad2[_SS_PAD2SIZE];
};
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,如果函数需要IPv4地址,它将只读取前4个字节(因为它假定结构是类型struct sockaddr
.否则它将读取IPv6的完整16个字节).
Ale*_*lke 10
在具有至少一个虚函数的C++类中,给出了TAG.该标签允许您访问dynamic_cast<>()
您的类派生的任何类,反之亦然.TAG是允许dynamic_cast<>()
工作的东西.或多或少,这可以是数字或字符串......
在C中,我们仅限于结构.但是,也可以为结构分配TAG.事实上,如果你看一下prole在他的答案中发布的所有结构,你会注意到它们都以2个字节(一个无符号的短)开头,它代表了我们称之为地址族的内容.这确切地定义了结构是什么,因此它的大小,字段等.
因此你可以这样做:
int bind(int fd, struct sockaddr *in, socklen_t len)
{
switch(in->sa_family)
{
case AF_INET:
if(len < sizeof(struct sockaddr_in))
{
errno = EINVAL; // wrong size
return -1;
}
{
struct sockaddr_in *p = (struct sockaddr_in *) in;
...
}
break;
case AF_INET6:
if(len < sizeof(struct sockaddr_in6))
{
errno = EINVAL; // wrong size
return -1;
}
{
struct sockaddr_in6 *p = (struct sockaddr_in6 *) in;
...
}
break;
[...other cases...]
default:
errno = EINVAL; // family not supported
return -1;
}
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,该函数可以检查len
参数以确保长度足以满足预期的结构,因此它们可以reinterpret_cast<>()
(就像在C++中调用的那样)指针.结构中的数据是否正确取决于调用者.在这方面没有太多选择.这些函数应该在使用数据之前验证所有类型的东西,并errno
在发现问题时返回-1 .
因此,实际上,您有一个struct sockaddr_in
或struct sockaddr_in6
那个(重新解释)强制转换为a struct sockaddr
和bind()
函数(和其他人)将该指针强制转换为a struct sockaddr_in
或者struct sockaddr_in6
在检查sa_family
成员并验证大小之后.
归档时间: |
|
查看次数: |
30459 次 |
最近记录: |