在我的 Mac OSX 10.74 上,我遇到了这种行为,我已经接近得出结论,这是 Mac OSX 的防火墙软件中的一个错误。基本上,在应用程序退出后,会话期间使用的多播 UDP 端口除了一个之外没有关闭。
出于本演示的目的,我设置了两个应用程序。一种叫做 UDPSender,它只是向两个多播组发送两条消息。以下代码段可以从 Mac 或 iOS 设备运行。GCDAsyncUdpSocket 是最新版本。
GCDAsyncUdpSocket *udpSocket1;
GCDAsyncUdpSocket *udpSocket2;
udpSocket1 = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
udpSocket2 = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
NSData *data = [@"A test message from socket1" dataUsingEncoding:NSUTF8StringEncoding];
[udpSocket1 sendData:data toHost:@"239.1.1.110" port:46110 withTimeout:-1 tag:1];
data = [@"A test message from socket2" dataUsingEncoding:NSUTF8StringEncoding];
[udpSocket2 sendData:data toHost:@"239.1.1.120" port:46120 withTimeout:-1 tag:1];
我为 Mac 创建了另一个名为 UDPReceiver 的应用程序。(这是行为不端)
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
GCDAsyncUdpSocket *udpSocket1;
GCDAsyncUdpSocket *udpSocket2;
udpSocket1 = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
udpSocket2 = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
NSError *error = nil;
// udpSocket1
if ([udpSocket1 bindToPort:46110 error:&error])
{
if (![udpSocket1 joinMulticastGroup:@"239.1.1.110" error:&error])
{
NSLog(@"udpSocket1 multicast failed to multicast group");
}
if (![udpSocket1 beginReceiving:&error])
{
[udpSocket1 close];
NSLog(@"udpSocket1 rrror starting server (recv): %@", error);
}
} else
{
NSLog(@"udpSocket1 rrror starting server (bind): %@", error);
// return;
}
// udpSocket2
if ([udpSocket2 bindToPort:46120 error:&error])
{
if (![udpSocket2 joinMulticastGroup:@"239.1.1.120" error:&error])
{
NSLog(@"udpSocket2 multicast failed to multicast group");
}
if (![udpSocket2 beginReceiving:&error])
{
[udpSocket2 close];
NSLog(@"udpSocket2 rrror starting server (recv): %@", error);
return;
}
} else
{
NSLog(@"udpSocket2 rrror starting server (bind): %@", error);
// return;
}
}
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data
fromAddress:(NSData *)address
withFilterContext:(id)filterContext
{
NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"Receiving: %@", msg);
}
像这样的测试序列:打开 Mac 的防火墙。启动 UDPReceiver,启动 UDPSender。在 UDPReceiver 机器上,Mac 的防火墙提示许可……选择允许。结果是两个正确的日志语句:
2012-08-07 19:56:53.594 UDPReceiver[290:403] Receiving: A test message from socket1
2012-08-07 19:56:53.595 UDPReceiver[290:403] Receiving: A test message from socket2
接下来,关闭 UDPReceiver,然后再次重新打开 UDPReceiver。您将立即看到此日志。
2012-08-07 19:39:13.639 UDPReceiver[810:403] udpSocket1 rrror starting server (bind): Error Domain=NSPOSIXErrorDomain Code=48 "Address already in use" UserInfo=0x7fc7b3109d20 {NSLocalizedDescription=Address already in use, NSLocalizedFailureReason=Error in bind() function}
如果此时重启 UDPSender,你会看到另一个日志输出:
2012-08-07 19:39:29.939 UDPReceiver[810:403] Receiving: A test message from socket2
我打开 Mac 终端并使用此命令查看活动端口: netstat -anf inet
. 第一张图是第一次执行 UDPReceiver。第二张图片是在 UDPReceiver 关闭之后。
我发现有两种方法可以解决这个问题:
- 重新启动我的 Mac。然后它将再次正常工作。但上述症状仍然存在。
- 完全关闭防火墙。这将彻底消除问题。
有没有人遇到过这种现象?任何建议如何(编程)解决这个问题?