![](/img/trans.png)
[英]What's the difference between sockaddr, sockaddr_in, and sockaddr_in6?
[英]How to create sockaddr from sockaddr_in / sockaddr_in6 structure
以下是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調用connect?
以編程方式,我們如何將
sockaddr_in
和sockaddr_in6
轉換為sockaddr
結構(填充其成員變量),然后使用sockaddr結構調用connect?
類型轉換不是轉換 。 您沒有進行任何轉換。 就像您提供的示例所示,您可以根據需要創建sockaddr_in
或sockaddr_in6
實例,然后將其原樣傳遞給connect()
。 您只是在類型轉換指向結構實例的指針 。 在內部, 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()
是,您也可以將其用於服務器。 只需在hints.ai_flags
字段中使用AI_PASSIVE
標志,然后使用生成的addrinfo
項調用socket()
和bind()
。
以編程方式如何將
sockaddr_in
和sockaddr_in6
轉換為sockaddr
您不能這樣做,因為sockaddr_in
和sockaddr_in6
都不能保證適合sockaddr
結構。
符合POSIX標准的系統將提供一個sockaddr_storage
被保證是足夠大以保存任何類型的類型sockaddr
結構 :
<sys/socket.h>
標頭應定義sockaddr_storage
結構,該結構應為:
足夠大以容納所有受支持的協議特定的地址結構
在適當的邊界處對齊,以便可以將指向它的指針轉換為指向協議特定地址結構的指針,並用於訪問那些結構的字段而不會出現對齊問題
sockaddr_storage結構應至少包括以下成員:
sa_family_t ss_family
當一個指針指向一個
sockaddr_storage
結構被強制轉換為指針sockaddr
結構中,ss_family
所述的場sockaddr_storage
結構應映射到sa_family
所述的字段sockaddr
結構。 當將指向sockaddr_storage
結構的指針轉換為指向協議特定的地址結構的指針時,ss_family
字段應映射到該結構的字段上,該字段的類型為sa_family_t
並標識協議的地址族。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.