【问题标题】:Testing for IP address reachability from the iPhone测试 iPhone 的 IP 地址可达性
【发布时间】:2026-02-14 12:55:01
【问题描述】:

我继承了一个 iPhone 应用程序/项目,它打开了与另一台设备的套接字连接(想想网络摄像头)。只要设备可以通过 wifi 网络访问,这就可以正常工作。但是,如果无法访问,应用程序会挂起调用“connect”。

(为了清楚起见,删除了错误检查。)

-(void)connect_to_control:(NSTimer*) timer

{

clientsock_fd = socket(AF_INET, SOCK_STREAM, 0);
int no_delay = 1;
setsockopt(clientsock_fd, IPPROTO_TCP, TCP_NODELAY, &no_delay, 4);

struct sockaddr_in the_addr;
memset((void *)&the_addr, 0, sizeof(the_addr));
the_addr.sin_family = AF_INET;
the_addr.sin_port = htons(25556);
const char* server_addr = "192.168.3.22";
unsigned long ip_addr = inet_addr(server_addr);


the_addr.sin_addr.s_addr = ip_addr;
int err_test = connect(clientsock_fd, (const struct sockaddr*)&the_addr, sizeof(the_addr)); 

}

我的第一个想法是“ping”该地址以查看它是否可以访问。到目前为止,我已经发现了 Apple 的“Reachability”示例,但这并不能确定地址是否可以访问,只有当网络可以访问(模拟器除外)和一个旧的 Apple 示例“SimplePing”,它使用的头文件不是包含在 iPhone SDK 中。

我拥有数十年的 C++/C# 经验,但我是一名 iPhone 菜鸟,试图帮助朋友的小公司及时为重要的贸易展调试一些东西。提前致谢。

【问题讨论】:

    标签: iphone objective-c


    【解决方案1】:

    请参阅this question 了解如何将套接字置于非阻塞模式。

    这可能是您想要做的,因为主机可能会响应 ping,即使它没有在特定的套接字上侦听,反之亦然。

    【讨论】:

    • 这个答案并没有真正提供如何做到这一点的全部细节。
    【解决方案2】:

    首先将套接字设置为非阻塞模式,这意味着连接总是会立即返回:

    lags = fcntl(sock,F_GETFL,0);
    fcntl(sock,F_SETFL, flags | O_NONBLOCK)
    

    然后你使用带有超时值的select语句来检查连接是否成功:

    select(FD_SETSIZE,0,&wset,0,&timeout)
    

    你可以找到完整的解释 的non blocking sockets here

    【讨论】:

    • OP here:谢谢,这看起来很有希望。我今天早上正在尝试。
    【解决方案3】:

    无论出于何种原因,我都无法使用“选择”工作获得非阻塞解决方案。 (但感谢你们两位的有益回复。)我最终使用了一个套接字选项,让我可以指定更短的超时时间。

    setsockopt(clientsock_fd, IPPROTO_TCP, TCP_CONNECTIONTIMEOUT, &timeout, sizeof(timeout));
    

    为了完整起见,这就是我最终得到的结果(为了清楚起见,删除了错误检查):

    -(void)connect_to_control:(NSTimer*) timer
    

    {

    clientsock_fd = socket(AF_INET, SOCK_STREAM, 0);
    int no_delay = 1;
    int result = setsockopt(clientsock_fd, IPPROTO_TCP, TCP_NODELAY, &no_delay, 4);
    
    // *** Set timeout value to stop hanging ***
    struct timeval timeout; 
    timeout.tv_sec =1;
    timeout.tv_usec =0; 
    result = setsockopt(clientsock_fd, IPPROTO_TCP, TCP_CONNECTIONTIMEOUT, &timeout, sizeof(timeout));
    
    struct sockaddr_in the_addr;
    memset((void *)&the_addr, 0, sizeof(the_addr));
    the_addr.sin_family = AF_INET;
    the_addr.sin_port = htons(25556);
    const char* server_addr = "192.168.3.22";
    unsigned long ip_addr = inet_addr(server_addr);
    the_addr.sin_addr.s_addr = ip_addr;
    
    int err_test = connect(clientsock_fd, (const struct sockaddr*)&the_addr, sizeof(the_addr)); // hangs here when address can't be reached!
    

    注意:我必须升级到 OS 3.0 才能使用 TCP_CONNECTIONTIMEOUT。 TCP_CONNECTIONTIMEOUT 在 OS 3.0 SDK 标头的“tcp.h”中定义,但在 OS 2.1 中没有。它没有在模拟器头文件中定义,只有设备头文件。

    【讨论】: