如何从/sockaddr\u/sockaddr\u in6结构中创建sockaddr
以下是IPv6和IPv4客户端代码示例代码的摘录: IPv6如何从/sockaddr\u/sockaddr\u in6结构中创建sockaddr,c,sockets,networking,C,Sockets,Networking,以下是IPv6和IPv4客户端代码示例代码的摘录: 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
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。由于它们都将结构转换为struct sockaddr结构-通过编程,我们如何将中的sockaddr_和中的sockaddr_转换为sockaddr结构(填充其成员变量),然后调用connect with sockaddr sturcure
通过编程,我们如何将中的sockaddr\u和
中的sockaddr\u转换为sockaddr
您不能,因为sockaddr\u in
和sockaddr\u in 6
都不能保证适合sockaddr
结构
:
标题应定义sockaddr\u存储
结构,其应为:
- 足够大,可以容纳所有受支持的特定于协议的地址结构
- 在适当的边界对齐,以便指向它的指针可以转换为指向特定于协议的地址结构的指针,并用于
在没有对齐问题的情况下访问这些结构的字段
sockaddr_存储结构应至少包括以下内容
成员:
sa_family_t ss_family
指向sockaddr\u存储
结构的指针被强制转换为指针时
对于sockaddr
结构,将
sockaddr\u存储
结构应映射到
sockaddr
结构。当指针指向sockaddr\u存储器时
结构被强制转换为指向协议特定地址的指针
结构,ss_系列
字段应映射到该
结构类型为sa_family\u t
,用于标识
协议的地址族
通过编程,我们如何将
中的sockaddr\u和
中的sockaddr\u转换为sockaddr
结构(填充其成员变量),然后调用connectwithsockaddr结构
类型转换不是转换。你没有转换任何东西。正如您提供的示例所示,您可以根据需要在
中或在6实例中创建一个sockaddr\u,然后将其原样传递给connect()
。您只是在类型转换指向结构实例的指针。在内部,connect()
将查看其输入addr
的sa_系列
字段,并根据需要将addr
类型转换回sockaddr_in
或sockaddr_in 6
,以访问数据字段
我的目标是为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;
}
但是,更好的解决方案是使用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;
}
getaddrinfo()
的好处在于,您也可以将其用于服务器。只需在提示.AI_flags
字段中使用AI_PASSIVE
标志,然后使用生成的addrinfo
项调用socket()
和bind()
我怀疑,带有memcpy(&addr,&addr\in,sizeof(struct sockdr)
。使用getaddrinfo()
用于以独立于协议的方式填充套接字地址结构。“连接API”您计划将什么传递给此API?感谢如何使用getaddrinfo()API以独立于协议的方式填充结构?“how can…”:您可能想看看。是哪一个?不保证还是真的?@user207421我不知道“应定义sockaddr_存储
结构,该结构应足够大,以容纳所有支持的协议特定地址结构”不清楚。
int s = doConnect(AF_INET6, "::1", 5000);
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);