我有一个基于TCP的程序,支持IPv4
和IPv6
。所以我在代码中使用了"sockaddr_storage
“。
在客户端TCP端,我需要将客户端端口固定到一个特定的端口,因此我需要将套接字绑定到该地址。
struct sockaddr_storage local_addrs; //for local address
if (sc->domain == AF_INET) {
(*(struct sockaddr_in*)&local_addrs).sin_family = AF_INET;
(*(struct sockaddr_in*)&local_addrs).sin_addr.s_addr = inet_addr(INADDR_ANY);
(*(struct sockaddr_in*)&local_addrs).sin_port = htons(tcp_port);
}
else{
(*(struct sockaddr_in6*)&local_addrs).sin6_family = AF_INET6;
(*(struct sockaddr_in6*)&local_addrs).sin_addr.s_addr = inet_addr(IN6ADDR_ANY_INIT);
(*(struct sockaddr_in6*)&local_addrs).sin6_port = htons(tcp_port);
}
local_addr_size = sizeof(local_addrs);
if (( ret = bind(sockfd, (struct sockaddr *)&local_addrs, local_addr_size)) < 0 ) {
....//error
}
如何初始化struct sockaddr_storage local_addrs
?我需要为这个结构分配内存吗?
顺便说一下,下面这行还不起作用。仍然在尝试找出如何将客户端sokcet绑定到任何可能的IPv6地址。
(*(struct sockaddr_in6*)&local_addrs).sin_addr.s_addr = inet_addr(IN6ADDR_ANY_INIT);
发布于 2018-06-06 05:14:18
您所显示的代码基本上是正确的,因为您需要将一个sockaddr_storage
类型转换为您想要填充的特定sockaddr_...
类型。
然而,在sockaddr_in6
的情况下,IN6ADDR_ANY_INIT
部分是错误的。改用下面的代码:
(*(struct sockaddr_in6*)&local_addrs).sin6_addr = in6addr_any;
IN6ADDR_ANY_INIT
是一个只能在编译时静态声明中使用的宏,例如:
struct sockaddr_in6 in6 = {AF_INET6, port, 0, IN6ADDR_ANY_INIT, 0};
struct in6_addr addr = IN6ADDR_ANY_INIT;
在运行时不能在赋值中使用IN6ADDR_ANY_INIT
,例如:
struct sockaddr_in6 in6;
in6.sin6_addr = IN6ADDR_ANY_INIT; // ERROR
struct in6_addr addr;
addr = IN6ADDR_ANY_INIT; // ERROR
另一方面,in6addr_any
是一个全局变量,可以在运行时在赋值中使用。
而且,您不需要对sockaddr_storage
结构执行malloc
。
也就是说,我建议使用一些局部变量来使代码更容易阅读:
if (sc->domain == AF_INET) {
struct sockaddr_in *in4 = (struct sockaddr_in*) &local_addrs;
in4->sin_family = AF_INET;
in4->sin_addr.s_addr = INADDR_ANY; // <-- inet_addr() is not needed for INADDR_ANY
in4->sin_port = htons(tcp_port);
}
else {
struct sockaddr_in6 *in6 = (struct sockaddr_in6*) &local_addrs;
in6->sin6_family = AF_INET6;
in6->sin6_addr = in6addr_any;
in6->sin6_port = htons(tcp_port);
/* note: sockaddr_in6 also has sin6_flowinfo and sin6_scope_id
fields that you may have to fill, too...
in6->sin6_flowinfo = ...;
in6->sin6_scope_id = ...;
*/
}
或者,改用union
:
union sockaddr_types {
struct sockaddr_storage storage;
struct sockaddr addr;
struct sockaddr_in in4;
struct sockaddr_in6 in6;
};
union sockaddr_types local_addrs;
if (sc->domain == AF_INET) {
local_addrs.in4.sin_family = AF_INET;
local_addrs.in4.sin_addr.s_addr = INADDR_ANY;
local_addrs.in4.sin_port = htons(tcp_port);
}
else {
local_addrs.in6.sin6_family = AF_INET6;
local_addrs.in6.sin6_addr = in6addr_any;
local_addrs.in6.sin6_port = htons(tcp_port);
/*
local_addrs.in6.sin6_flowinfo = ...;
local_addrs.in6.sin6_scope_id = ...;
*/
}
if ((ret = bind(sockfd, &local_addrs.addr, sizeof(local_addrs))) < 0) {
//error...
}
无论采用哪种方式,在填充所需字段之前,您都应该考虑将整个sockaddr_storage
置零,以预先填充未使用的字段:
memset(&local_addrs, 0, sizeof(local_addrs));
https://stackoverflow.com/questions/50707444
复制相似问题