我一直在尝试为简单的局域网通信创建一个广播客户端,而且我已经制作了一个相当简单的客户端和服务器,它具有基本的数据序列化接口。我一直在弄清楚如何获得我正在使用的任何工作站的“定向广播”地址,以便我可以设置聊天。我是网络新手,所以我在这个领域没有很多经验。我尝试查找示例,但我发现的大多数都不是我想要的。一切都在环回地址上工作,广播是我目前唯一的问题区域。
我从Beej's tutorial中学到了基本的想法,它简要解释了广播数据包的确切内容以及防火墙,网络负载等一些陷阱,也许还有一些不太明显的陷阱。然后我通过一个更加面向winsock的网站Winsock's Programmer's FAQ增强了这些知识,这使得它与我的Windows特定程序更具相关性。
虽然我理解广播背后的想法,但我无法以与工作站无关的方式修改程序,并将数据包从客户端广播到服务器。从我读过的几个SO问题和上面提到的Winsock FAQ中,我发现“获取本地IP地址”的想法并不完全是黑白分明的。由于用户可能有多种不同的网络方式或者您可以使用不同的地址。这是困扰我如何妥善处理的主要问题。
我用来包装此行为的当前函数是:
extern void WINAPI setup_connection( connection_data * data )
{
char host_name[128] = { 0 };
struct in_addr host_address;
struct in_addr broadcast_address;
if ( gethostname( &host_name[0], sizeof( host_name ) ) == HOST_NOT_FOUND )
{
winsock_error( "Getting host name", WSAGetLastError( ), FALSE );
destroy_winsock_data( data );
exit( 1 );
}
if ( !( data->host_info = gethostbyname( &host_name[0] ) ) )
{
winsock_error( "Getting host by name", WSAGetLastError( ), FALSE );
destroy_winsock_data( data );
exit( 1 );
}
host_address = *( ( struct in_addr * )data->host_info->h_addr );
broadcast_address.S_un.S_addr = ( host_address.S_un.S_addr & NETMASK ) | ( ~( NETMASK ) );
data->broadcast_address.sin_family = AF_INET;
data->broadcast_address.sin_port = htons( PORT );
data->broadcast_address.sin_addr = broadcast_address;
return;
}
主机名似乎是正确的,但gethostbyname显然返回了一个垃圾值。如果我尝试检索返回的IP地址,则表示“地址无效”。由于某些原因,发送调用不会出错,但数据包永远不会发送给我理解。
如果您想知道,我将套接字设置为广播如下:
extern int WINAPI set_socket_to_broadcast( int socket, BOOL setting )
{
char broadcast = ( setting ? '1' : '0' );
if ( setsockopt( socket, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof( char ) ) == SOCKET_ERROR )
{
winsock_error( "Setting Broadcast", WSAGetLastError( ), FALSE );
return -1;
}
return 0;
}
然后,如果你想知道我的connection_data结构是什么,我就这样声明:
typedef struct connection_data
{
struct sockaddr_in broadcast_address;
struct hostent * host_info;
int socket;
} connection_data;
如果您需要更多详细信息,我明天可以再次查看和发布。
答案 0 :(得分:1)
这里的主要问题是网络掩码不是常量,它是您可以检索的接口的属性。
答案 1 :(得分:1)
请勿使用gethostname()
和gethostbyname()
来检索本地IP地址。它并不总是有效,甚至可以报告虚假信息。不仅如此,它还不能让您访问子网信息,您需要计算广播IP地址。连接到网络的每个IP适配器都有自己的IP和子网,因此您必须使用与实际发送广播的适配器关联的值。使用特定于平台的API来枚举本地IP适配器。在Windows上,使用GetAdaptersInfo()
或GetAdapterAddresses()
。在基于* Nix的平台上,使用getifaddrs()
。其中任何一个都会为您提供IP和子网信息(getifaddrs()
甚至可以为您提供实际的广播IP)。