[英]How to find proper port for NSNetService on iOS?
我正在制作一個包含兩個組件的應用程序,一個iPhone組件和一個Mac組件。 他們應該通過bonjour互相溝通。 我在Mac端使用以下代碼來查找服務的端口:
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端使用此代碼並在模擬器中運行應用程序,連接工作正常。 但是,當我嘗試在實際的iPhone上運行此代碼時,我發現iPhone上沒有NSSocketPort。 當我嘗試使用端口9876啟動服務時,Mac應用程序在嘗試連接時顯示連接被拒絕錯誤。 那么如何在不使用NSSocketPort的情況下找到要使用的端口?
好的,我查看了Apple的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);
}
}
我拿出了很多錯誤的東西,所以它可能不是最佳的,但它可以工作。
從iOS 7開始,NSNetService可以為您創建和綁定套接字。 如果使用端口0初始化,它將選擇一個隨機端口:
NSNetService *service = [[NSNetService alloc] initWithDomain:@"local." type:@"_test._tcp." name:@"Test Service" port:0];
[service publishWithOptions:NSNetServiceListenForConnections];
該服務將在建立連接時將netService:didAcceptConnectionWithInputStream:outputStream:
發送到其委托。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.