EXC_BAD_ACCESS调用CFSocketSendData

时间:2011-12-01 18:25:50

标签: objective-c sockets

我正在使用此类的实例将必要的值传递给发送套接字数据的函数:

@interface SsdpParameters : NSObject
{
    CFDataRef msg;
    CFDataRef addr;
    CFSocketRef sock;
}

@property CFDataRef msg;
@property CFDataRef addr;
@property CFSocketRef sock;

@end

这是负责发送套接字数据的函数:

-(void)SendSsdpResponse:(id)parameters
{
    SsdpParameters *params = parameters;
    CFDataRef msg = (CFDataRef)params.msg;
    CFDataRef addr = (CFDataRef)params.addr;
    CFSocketRef sock = (CFSocketRef)params.sock;

    CFSocketError err = CFSocketSendData (sock, addr, msg, 0);  // Program received signal:  "EXC_BAD_ACCESS".

    if (err)
    {
        NSLog(@"Error sending Valid Response");
    }
}

此函数设置套接字并在1秒延迟后调用SendSsdpResponse:

- (void) sendValidResponses
{
    NSMutableString *message = nil;
CFSocketRef sock = [self newSSDPSendSocket];
if(sock != nil)
    {
        struct sockaddr_in SSDPaddr;
        memset(&SSDPaddr, 0, sizeof(SSDPaddr));
        SSDPaddr.sin_family=AF_INET;
        SSDPaddr.sin_addr.s_addr=inet_addr(SSDP_ADDRESS);
        SSDPaddr.sin_port=htons(SSDP_PORT);

        // Loop through list, sending SSDP
        for (NSString *aKey in list)
        {
            message = [[NSMutableString alloc] initWithString:@"NOTIFY * HTTP/1.1\r\n"];

        // Append more lines to message.

            CFDataRef addr = CFDataCreate(NULL, (const UInt8*)&SSDPaddr, sizeof(SSDPaddr));
            CFDataRef msg  = CFDataCreate(NULL, (const UInt8*)[message UTF8String], [message lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);

            SsdpParameters *parameters = [[SsdpParameters alloc] init];
            parameters.msg = msg;
            parameters.addr = addr;
            parameters.sock = sock;

            [self performSelector:@selector(SendSsdpResponse:) withObject:parameters afterDelay:1.0];

            CFRelease(addr);
            CFRelease(msg);
            [message release];
        }

        CFRelease(sock);
    }
}

正如您在评论中看到的那样,在SendSsdpResponse中,我得到了一个" EXC_BAD_ACCESS"尝试调用CFSendSocketData时出错。我怀疑它是因为我正在"传递" sockaddrmsg,运行时不喜欢这个。在将CF数据类型的变量传递给其他函数之前,我遇到过这个问题。我还没有找到答案,希望有人能在这里帮助我了解幕后发生的事情。

谢谢!

2 个答案:

答案 0 :(得分:2)

EXC_BAD_ACCESS错误通常表示您正在尝试在已经解除分配的实例上调用方法。如果您没有正确retain个变量,通常会出现这种情况,尤其是当它们在函数之间传递时。

执行带延迟的选择器时,在此行:

[self performSelector:@selector(SendSsdpResponse:) withObject:parameters afterDelay:1.0];

您为方法提供了parameters变量,该变量具有您提供的标头中定义的属性。问题是在performSelector:方法之后,您正在释放引用addrmsg的内存。由于您正在延迟执行此选择器, addr和msg指向的内存在使用之前将被释放

因此,一旦释放了这个内存,它就不再是SsdpParameters对象中的“好”了。您应该(在这些属性的setter中,在SsdpParameters对象上)复制此内存,以便原始调用者可以安全地释放它。

您应该调查此功能:

CFDataRef CFDataCreateCopy (
   CFAllocatorRef allocator,
   CFDataRef theData
);

然后,你的二传手看起来像:

@implementation SsdpParameters

...

- (void)setMsg:(CFDataRef)m {
    // You should also release msg if it already exists
    msg = CFDataCreateCopy(CFAllocatorGetDefault(), m);
}

...

@end

答案 1 :(得分:0)

要进行问题排查,请尝试将呼叫替换为

[self performSelector:@selector(SendSsdpResponse:) withObject:parameters afterDelay:1.0];

立即致电

[self SendSsdpResponse:parameters];

看看会发生什么。

如果仍然显示“EXC_BAD_ACCESS”,则表示您的参数设置不正确。另一方面,如果没有出现错误,则表示参数对象最初是正常的,但在延迟完成之前变为无效。例如,参数对象是保留还是复制“addr”和“msg”?