如何从/sockaddr\u/sockaddr\u in6结构中创建sockaddr

如何从/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

以下是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, 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);