Android上的select()始终返回false

时间:2016-12-10 22:05:31

标签: android c++ sockets android-ndk

我目前正在用C ++建立一个基于UDP的网络库。

我打算使用它们的方法是运行同一个应用程序的两个实例 一个在Windows上,另一个在Android上。

Android实例应该发送一个在Windows上收到的广播消息 然后在两端打开单播套接字并开始通信。

但是,现在,我正在测试两个方向的简单广播。

根据我发现的,为了从套接字接收消息,必须使用本地IP地址调用bind()函数(格式为" 192.168.x.x")以及要收听的端口号。

在Windows上,我可以使用以下代码找到此本地IP地址:

char* UDPSocketPC::getLocalAddress()
{
    hostent *thisHost = gethostbyname ( "" );
    char buf [100];
    _itoa_s ( **thisHost->h_addr_list, buf, 10 );
    return inet_ntoa ( *reinterpret_cast<struct in_addr * >(*thisHost->h_addr_list) );
    //returns an ip address in the form of "192.168.0.3"
}

在Android上,gethostbyname功能不存在,hostent类也不存在。

我现在使用的是INADDR_ANY(0.0.0.0),INADDR_BROADCAST(255.255.255.255)和INADDR_LOOPBACK(127.0.0.1)。这些地址都没有收到我发送的广播。

其他所有内容似乎都设置正确 在Windows上,我接收从Windows和Android发送的广播 在Android上我没有收到。

这个问题的主要困难在于绝大多数在线文档都是针对Unix套接字或WinSock套接字,因此很难为NDK找到一个很好的例子。

提前感谢您的帮助。

编辑:

我已经取得了一些进展,看起来我遇到的问题实际上与我尝试使recvfrom ()功能无阻塞有关

以下是我在Windows上select()函数的实现:

fd_set sockets = fd_set ( );
sockets.fd_array [0] = socketPTR;
sockets.fd_count = 1;
fd_set empty = fd_set ( );
const timeval timeout = { timeoutSec, timeoutMicroSec };
return select ( 0, &sockets, &empty, &empty, &timeout ) > 0;

以下是我在Android上的表现:

fd_set sockets = fd_set ( );
FD_ZERO ( &sockets );
FD_SET ( socketPTR, &sockets );
fd_set empty = fd_set ( );
FD_ZERO ( &empty );
timeval timeout = { timeoutSec, timeoutMicroSec };
return select ( 0, &sockets, &empty, &empty, &timeout ) > 0;

Windows实现几乎完全符合我的预期,当没有数据可供读取时返回false,当队列中至少有一条消息时返回true。 但是在Android上似乎总是返回false。

通过暂时从Android中删除呼叫,我可以在两个平台上从两个平台发送和接收消息 但是现在这个调用在Android上是阻塞的(这不是理想的,因为我想让线程做其他事情而没有数据可用)。

我会在Android上查找有关select()功能的更多信息,以使其真正有效。

1 个答案:

答案 0 :(得分:3)

您没有为select()的第一个参数提供值。在Windows上忽略该参数,但在其他平台上不会忽略它。每the documentation

  

nfds是三组中任何一组中编号最大的文件描述符,加上1。

因此,在您的示例中,您需要将参数设置为socketPTR+1

此外,不要为未使用的参数提供空fd_set结构。请改用NULL

  

如果没有为相应的事件类监视文件描述符,则可以将三个文件描述符集中的每一个指定为NULL。

此外,即使在Windows上,也始终使用FD_ZERO()FD_SET()。这有助于促进跨fd_set使用不同布局的平台的代码可移植性。

请尝试使用此代码:

fd_set sockets;
FD_ZERO( &sockets );
FD_SET( socketPTR, &sockets );
timeval timeout = { timeoutSec, timeoutMicroSec };
return select ( socketPTR+1, &sockets, NULL, NULL, &timeout ) > 0;