我正在尝试编写一个使用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);
谢谢, 弗兰克
答案 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));