2012-07-27 3 views
3

저는 iPhone 구성 요소와 Mac 구성 요소의 두 가지 구성 요소로 응용 프로그램을 만들고 있습니다. 그들은 봉쥬르 (bonjour)를 통해 서로 의사 소통하기로되어 있습니다.iOS에서 NSNetService에 적합한 포트를 찾는 방법은 무엇입니까?

NSSocketPort *socket = [[NSSocketPort alloc] init]; 
struct sockaddr *addr = (struct sockaddr *)[[socket address] bytes]; 
int port = 9876; 
if(addr->sa_family == AF_INET) { 
    port = ntohs(((struct sockaddr_in *)addr)->sin_port); 
} else if(addr->sa_family == AF_INET6) { 
    port = ntohs(((struct sockaddr_in6 *)addr)->sin6_port); 
} else { 
    [socket release]; 
    socket = nil; 
    NSLog(@"The family is neither IPv4 nor IPv6. Can't handle!!!"); 
} 

나는 또한 아이폰 끝에이 코드를 사용하여 시뮬레이터에서 응용 프로그램을 실행 할 수 있으며, 연결이 잘 작동 : 나는 서비스에 대한 포트를 찾기 위해 맥 끝에 다음 코드를 사용합니다. 그러나 실제 iPhone에서이 코드를 실행하려고하면 NSSocketPort를 iPhone에서 사용할 수 없다는 것을 알았습니다. 포트 9876을 사용하여 서비스를 시작하려고하면 Mac 응용 프로그램에서 연결을 시도 할 때 연결 거부 오류가 표시됩니다. 그렇다면 NSSocketPort를 사용하지 않고 사용할 포트를 어떻게 찾을 수 있습니까?

답변

4

가 좋아 나는 애플의 WiTap 코드를 보니 약간 포트 점점 나 자신에게하는 방법을 쓰기를 수정 : 아마 최적되지 그래서 나는 오류 물건을 많이 꺼내

- (int) getPort { 
CFSocketContext socketCtxt = {0, self, NULL, NULL, NULL}; 

// Start by trying to do everything with IPv6. This will work for both IPv4 and IPv6 clients 
// via the miracle of mapped IPv4 addresses.  

CFSocketRef witap_socket = CFSocketCreate(kCFAllocatorDefault, PF_INET6, SOCK_STREAM, IPPROTO_TCP, kCFSocketAcceptCallBack, nil, &socketCtxt); 
uint32_t protocolFamily; 

if (witap_socket != NULL) // the socket was created successfully 
{ 
    protocolFamily = PF_INET6; 
} else // there was an error creating the IPv6 socket - could be running under iOS 3.x 
{ 
    witap_socket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketAcceptCallBack, nil, &socketCtxt); 
    if (witap_socket != NULL) 
    { 
     protocolFamily = PF_INET; 
    } 
} 

/*if (NULL == witap_socket) { 
    if (error) *error = [[NSError alloc] initWithDomain:TCPServerErrorDomain code:kTCPServerNoSocketsAvailable userInfo:nil]; 
    if (witap_socket) CFRelease(witap_socket); 
    witap_socket = NULL; 
    return NO; 
}*/ 


int yes = 1; 
setsockopt(CFSocketGetNative(witap_socket), SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes)); 

// set up the IP endpoint; use port 0, so the kernel will choose an arbitrary port for us, which will be advertised using Bonjour 
if (protocolFamily == PF_INET6) 
{ 
    struct sockaddr_in6 addr6; 
    memset(&addr6, 0, sizeof(addr6)); 
    addr6.sin6_len = sizeof(addr6); 
    addr6.sin6_family = AF_INET6; 
    addr6.sin6_port = 0; 
    addr6.sin6_flowinfo = 0; 
    addr6.sin6_addr = in6addr_any; 
    NSData *address6 = [NSData dataWithBytes:&addr6 length:sizeof(addr6)]; 

    CFSocketSetAddress(witap_socket, (CFDataRef)address6); 
    /*if (kCFSocketSuccess != CFSocketSetAddress(witap_socket, (CFDataRef)address6)) { 
     if (error) *error = [[NSError alloc] initWithDomain:TCPServerErrorDomain code:kTCPServerCouldNotBindToIPv6Address userInfo:nil]; 
     if (witap_socket) CFRelease(witap_socket); 
     witap_socket = NULL; 
     return NO; 
    }*/ 

    // now that the binding was successful, we get the port number 
    // -- we will need it for the NSNetService 
    NSData *addr = [(NSData *)CFSocketCopyAddress(witap_socket) autorelease]; 
    memcpy(&addr6, [addr bytes], [addr length]); 
    return ntohs(addr6.sin6_port); 

} else { 
    struct sockaddr_in addr4; 
    memset(&addr4, 0, sizeof(addr4)); 
    addr4.sin_len = sizeof(addr4); 
    addr4.sin_family = AF_INET; 
    addr4.sin_port = 0; 
    addr4.sin_addr.s_addr = htonl(INADDR_ANY); 
    NSData *address4 = [NSData dataWithBytes:&addr4 length:sizeof(addr4)]; 

    CFSocketSetAddress(witap_socket, (CFDataRef)address4); 
    /*if (kCFSocketSuccess != CFSocketSetAddress(witap_socket, (CFDataRef)address4)) { 
     if (error) *error = [[NSError alloc] initWithDomain:TCPServerErrorDomain code:kTCPServerCouldNotBindToIPv4Address userInfo:nil]; 
     if (witap_socket) CFRelease(witap_socket); 
     witap_socket = NULL; 
     return NO; 
    }*/ 

    // now that the binding was successful, we get the port number 
    // -- we will need it for the NSNetService 
    NSData *addr = [(NSData *)CFSocketCopyAddress(witap_socket) autorelease]; 
    memcpy(&addr4, [addr bytes], [addr length]); 
    return ntohs(addr4.sin_port); 
} 

} 

을하지만, 그것은 작동 .

+1

이 코드는'CFSocketRef'를 누설합니다. – jonahb

+0

매번 새로운 연결을 만들거나 기존의 테스트를 할 때마다 매번 새로운 포트를 수신합니다. 맞습니까? – landonandrey

4

iOS 7부터 NSNetService는 소켓을 만들고 바인딩 할 수 있습니다. 연결이 설정되면이 서비스는 대리인에게 netService:didAcceptConnectionWithInputStream:outputStream:를 보내드립니다

NSNetService *service = [[NSNetService alloc] initWithDomain:@"local." type:@"_test._tcp." name:@"Test Service" port:0]; 
[service publishWithOptions:NSNetServiceListenForConnections]; 

: 포트 0으로 초기화 된 경우, 임의의 포트를 선택합니다.