ios - 确定某个端口的某个地址是否可达

时间:2013-02-07 14:58:10

标签: iphone ios objective-c ipad network-programming

我想知道我的服务器是否通过我的ios应用程序在线。这就是我正在做的事情:

Boolean result;
CFHostRef hostRef = CFHostCreateWithName(kCFAllocatorDefault, (__bridge CFDataRef)(serverIPAddress)); //serverIPAdress = "10.10.10.100:5010"

    if(hostRef) {
        result = CFHostStartInfoResolution(hostRef, kCFHostAddresses, NULL); // pass an error instead of NULL here to find out why it failed
    }

    if (!result) { //This means that the host was unreachable        
        return ;
    }

我的服务器在线,我可以稍后在代码中访问它(这意味着我与服务器的连接工作正常)。但是,我希望能够检测某个端口上的服务器是否可访问。

另外,如果我从ip地址中删除“:5010”,它会检测到我的服务器在线(它没有进入“!result”状态)并检测到我的服务器如果我将“10.10.10.253”对应于我网络上的无IP地址,则处于脱机状态。

如何确定我的服务器是否在线?

我看过这个问题:Reachability with Address - Server AND Port - iOS 5但它不起作用,因为无论我输入什么IP地址,它总是返回它是可以访问的

提前致谢

1 个答案:

答案 0 :(得分:1)

一种方法可能是打开与特定端口的套接字连接,以查看是否收到任何响应。如果没有,则目的地无法到达。例如

#include <arpa/inet.h> //for PF_INET, SOCK_STREAM, IPPROTO_TCP etc

CFRunLoopSourceRef gSocketSource;
void ConnectCallBack(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)
{
    UInt8 buffer[1024];
    bzero(buffer, sizeof(buffer));
    CFSocketNativeHandle sock = CFSocketGetNative(socket); // The native socket, used recv()

    //check here for correct connect output from server
    recv(sock, buffer, sizeof(buffer), 0);
    printf("Output: %s\n", buffer);

    if (gSocketSource)
    {
        CFRunLoopRef currentRunLoop = CFRunLoopGetCurrent();
        if (CFRunLoopContainsSource(currentRunLoop, gSocketSource, kCFRunLoopDefaultMode))
        {
            CFRunLoopRemoveSource(currentRunLoop, gSocketSource, kCFRunLoopDefaultMode);
        }
        CFRelease(gSocketSource);
    }

    if (socket) //close socket
    {
        if (CFSocketIsValid(socket))
        {
            CFSocketInvalidate(socket);
        }
        CFRelease(socket);
    }
}

void ConnectSocket()
{
    //socket
    CFSocketContext context = {0, NULL, NULL, NULL, NULL};
    CFSocketRef theSocket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketConnectCallBack , (CFSocketCallBack)ConnectCallBack, &context);

    //address
    struct sockaddr_in socketAddress;
    memset(&socketAddress, 0, sizeof(socketAddress));
    socketAddress.sin_len = sizeof(socketAddress);
    socketAddress.sin_family = AF_INET;
    socketAddress.sin_port = htons(5010);
    socketAddress.sin_addr.s_addr = inet_addr("10.10.10.253");

    gSocketSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, theSocket, 0);
    CFRunLoopAddSource(CFRunLoopGetCurrent(), gSocketSource, kCFRunLoopDefaultMode);

    CFDataRef socketData = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)&socketAddress, sizeof(socketAddress));
    CFSocketError status = CFSocketConnectToAddress(theSocket, socketData, 30); //30 second timeout
    //check status here
    CFRelease(socketData);
}

基本上,如果服务器在该端口无法访问,您很可能会获得CFSocketError状态的kCFSocketTimeout。如果您希望从服务器解析特定响应以确定服务器是否准备就绪,则在成功连接套接字时将调用ConnectCallBack函数。

这只是一个简单的例子,请确保不要通过调用主线程上的套接字连接来阻止UI,例如recv()