android - Android 上的 select() 总是返回 false

标签 android c++ sockets android-ndk

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

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

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

不过,现在我正在测试双向的简单广播。

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

在 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() 函数的更多信息,以使其实际工作。

最佳答案

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

nfds is the highest-numbered file descriptor in any of the three sets, plus 1.

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

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

Each of the three file descriptor sets may be specified as NULL if no file descriptors are to be watched for the corresponding class of events.

此外,始终使用 FD_ZERO()FD_SET(),即使在 Windows 上也是如此。这有助于促进代码在使用不同 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;

关于android - Android 上的 select() 总是返回 false,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41080808/

相关文章:

java - 由于找不到 tools.jar,运行 android 构建失败以响应 native 项目

java - Arraylist 索引越界异常

c++ - 出现 LNK2005 和 KNK1169 错误 - 包括一个类在另一个类中

java - tomcat 获得用于创建 ajp 连接器的套接字的最佳日志级别

java - 为什么不成功 “HTTP GET request with socket ” ?

android - 无法通过存储访问框架加载扩展名为 .gpx 的文件

android - 自定义 CheckBox 菜单项 ActionBar 不起作用

c++ - strcpy 没有在此范围内声明?

c++ - Boost.flyweight 和 Boost.MPL

c++ - 是否可以编写便于复制初始化的显式构造函数?