下面是IPv6和IPv4 clinet代码示例代码的摘录:
IPv6
int s;
struct sockaddr_in6 addr;
s = socket(AF_INET6, SOCK_STREAM, 0);
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(5000);
inet_pton(AF_INET6, "::1", &addr.sin6_addr);
connect(s, (struct sockaddr *)&addr, sizeof(addr));
IPv4
int s;
struct sockaddr_in addr;
s = socket(AF_INET, SOCK_STREAM, 0);
addr.sin_family = AF_INET;
addr.sin_port = htons(5000);
servaddr.sin_addr.s_addr = INADDR_ANY;
connect(s, (struct sockaddr *)&addr, sizeof(addr));
我的目标是为IPv6和IPv4地址编写一个用户定义的连接API。由于它们都将结构转换为sockaddr结构--以编程的方式--如何将sockaddr_in和sockaddr_in6转换为 sockaddr 结构(填充其成员变量),然后调用连接sockaddr sturcure?
发布于 2019-09-04 21:33:11
在编程上,我们如何将
sockaddr_in
和sockaddr_in6
转换为sockaddr
结构(填充其成员变量),然后用sockaddr结构调用connect?
类型转换不是转换。你不能改变任何事。正如您提供的示例所示,您根据需要创建了一个sockaddr_in
或sockaddr_in6
实例,然后将其作为-is传递给connect()
。您只是在键入指向struct实例的指针。在内部,connect()
将查看其输入addr
的sa_family
字段,并相应地将addr
类型转换回sockaddr_in
或sockaddr_in6
,以便根据需要访问数据字段。
我的目标是为IPv6和IPv4地址编写一个用户定义的连接API。
如果您想编写与协议无关的代码,您可以这样做:
int doConnect(int family, const char *ip, u_short port)
{
struct sockaddr_storage ss = {};
socklen_t addrlen;
switch (family)
{
case AF_INET:
{
struct sockaddr_in *addr = (struct sockaddr_in *) &ss;
addr->sin_family = AF_INET;
addr->sin_port = htons(port);
inet_pton(AF_INET, ip, &addr->sin_addr);
addrlen = sizeof(struct sockaddr_in);
break;
}
case AF_INET6:
{
struct sockaddr_in6 *addr = (struct sockaddr_in6 *) &ss;
addr->sin6_family = AF_INET6;
addr->sin6_port = htons(port);
inet_pton(AF_INET6, ip, &addr->sin6_addr);
addrlen = sizeof(struct sockaddr_in6);
break;
}
default:
return -1;
}
int s = socket(family, SOCK_STREAM_IPPROTO_TCP);
if (s != -1)
{
if (connect(s, (struct sockaddr *) &ss, addrlen) < 0)
{
close(s);
s = -1;
}
}
return s;
}
int s = doConnect(AF_INET, "127.0.0.1", 5000);
int s = doConnect(AF_INET6, "::1", 5000);
然而,更好的解决方案是使用getaddrinfo()
,让它根据实际解析的输入值为您分配正确的sockaddr
数据,例如:
int doConnect(const char *ip, u_short port)
{
struct addrinfo hints = {};
hints.ai_flags = AI_NUMERICHOST;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
struct addrinfo *addr;
char szPort[6];
sprintf(szPort, "%hu", port);
int s = -1;
int ret = getaddrinfo(ip, szPort, &hints, &addr);
if (ret == 0)
{
s = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (s != -1)
{
if (connect(s, addr->ai_addr, addr->ai_addrlen) == -1)
{
close(s);
s = -1;
}
}
freeaddrinfo(addr);
}
return s;
}
int s = doConnect("127.0.0.1", 5000);
int s = doConnect("::1", 5000);
getaddrinfo()
的好处在于,您也可以将它用于服务器。只需在AI_PASSIVE
字段中使用hints.ai_flags
标志,然后使用生成的addrinfo
项调用socket()
和bind()
。
发布于 2019-09-04 09:45:21
如何在编程上将
sockaddr_in
和sockaddr_in6
转换为sockaddr
您不能这样做,因为sockaddr_in
和sockaddr_in6
都不能保证适合sockaddr
结构。
<sys/socket.h>
标头应定义sockaddr_storage
结构,该结构应为:
sockaddr_storage结构至少应包括下列成员:
sa_family_t ss_family
当指向sockaddr_storage
结构的指针被转换为指向sockaddr
结构的指针时,sockaddr_storage
结构的ss_family
字段将映射到sockaddr
结构的sa_family
字段。当指向sockaddr_storage
结构的指针转换为指向特定于协议的地址结构的指针时,ss_family
字段将映射到该结构的字段上,该字段的类型为sa_family_t
并标识该协议的地址族。
https://stackoverflow.com/questions/57784632
复制相似问题