使用具有特定IP地址的UDP

时间:2014-12-23 01:57:48

标签: ios sockets networking udp

我正在尝试编写一个使用UDP与设备通信的iOS应用。该设备的文档说它在特定的IP地址224.4.0.1和特定的端口号上进行通信。

我很难找到在特定IP地址上发送和接收UDP数据包的正确方法。这甚至可能吗?

我写了一些测试代码,可以从一个iOS设备发送UDP数据包,然后在另一个设备上监听。只要我将发送IP地址指定为INADDR_BROADCAST并将接收地址指定为INADDR_ANY,我编写的代码就可以工作。一旦我将其中一个或两个更改为224.4.0.1地址,它就不再有效(发送方不报告任何错误,但接收方永远不会收到数据包)。

我的理解是224.4.0.1在为多播保留的IP地址范围内。我确保在绑定它之前在侦听套接字上设置SO_REUSEADDR选项。

我试图最终使用的设备是在我的网络上,但到目前为止还没有回复我试图发送的任何内容。在我担心设备的具体情况之前,我想让我的测试用例使用两部iPhone。

我直接使用Berkeley套接字和/或用CFSocket包装它们。我已经在早期的项目中成功地使用了这些TCP接口,所以我对它们的工作方式非常满意。

以下是设置发送套接字的代码:

    struct sockaddr_in sin_send;
    memset(&sin_send, 0, sizeof(sin_send));
    sin_send.sin_len = sizeof(sin_send);
    sin_send.sin_family = AF_INET;
    sin_send.sin_port = htons(PORT_SEND);
    //sin_send.sin_addr.s_addr = htonl(INADDR_BROADCAST);
    inet_aton([@"224.4.0.1" UTF8String], &sin_send.sin_addr);

    int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

    int reuse = 1;
    NSLog(@"reuse %d", setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*) &reuse, sizeof(reuse)));
    NSLog(@"connect %d", connect(sock, (const struct sockaddr *) &sin_send, sizeof(sin_send)));

    _sendSocket = CFSocketCreateWithNative(kCFAllocatorDefault, sock, kCFSocketWriteCallBack, socketWriteCallBack, &context);

    if (!CFSocketIsValid(_sendSocket)) {
        NSLog(@"Send socket is not valid");
        return;
    }

    // Disable "nagling"
    CFSocketNativeHandle ssock = CFSocketGetNative(_sendSocket);
    int i = -1;
    setsockopt(ssock, IPPROTO_TCP, TCP_NODELAY, (char*) &i, sizeof(int));

    // Enable broadcast
    int broadcast = 1;
    setsockopt(ssock, SOL_SOCKET, SO_BROADCAST, (char*) &broadcast, sizeof(int));

这是接收套接字:

    struct sockaddr_in sin_read;
    memset(&sin_read, 0, sizeof(sin_read));
    sin_read.sin_len = sizeof(sin_read);
    sin_read.sin_family = AF_INET;
    sin_read.sin_port = htons(PORT_READ);
    //sin_read.sin_addr.s_addr = INADDR_ANY;
    inet_aton([@"224.4.0.1" UTF8String], &sin_read.sin_addr);

    int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

    int reuse = 1;
    NSLog(@"reuse %d", setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*) &reuse, sizeof(reuse)));
    NSLog(@"bind %d", bind(sock, (const struct sockaddr *) &sin_read, sizeof(sin_read)));

    int broadcast = 1;
    setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*) &broadcast, sizeof(int));

    int flags;
    flags = fcntl(sock, F_GETFL);
    NSLog(@"fcntl %d", fcntl(sock, F_SETFL, flags | O_NONBLOCK));

    _readSocket = CFSocketCreateWithNative(kCFAllocatorDefault, sock, kCFSocketAcceptCallBack | kCFSocketDataCallBack | kCFSocketReadCallBack, socketReadCallBack, &context);

谢谢, 弗兰克

1 个答案:

答案 0 :(得分:1)

解决方案是将我的侦听套接字绑定到INADDR_ANY,但随后使用setsockopt和IP_ADD_MEMBERSHIP选项以确保它侦听所需的IP地址。

    struct ip_mreq mreq;
    memset(&mreq, 0, sizeof(mreq));
    inet_aton([@"224.4.0.1" UTF8String], &mreq.imr_multiaddr);
    mreq.imr_interface.s_addr = INADDR_ANY;
    setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));