/ / Comment trouver le bon port pour NSNetService sur iOS? - iphone, macos, réseaux, bonjour, nssocketport

Comment trouver le port approprié pour NSNetService sur iOS? - iphone, macos, réseautage, bonjour, nssocketport

Je crée une application avec deux composants, un iPhoneet un composant Mac. Ils sont censés communiquer entre eux via bonjour. J'utilise le code suivant du côté Mac pour trouver un port pour le service:

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!!!");
}

Je peux également utiliser ce code à la fin de l'iPhone etexécutez l'application dans le simulateur et la connexion fonctionne correctement. Cependant, lorsque j'ai essayé d'exécuter ce code sur un iPhone réel, j'ai découvert que NSSocketPort n'est pas disponible sur l'iPhone. Lorsque j'essaie de démarrer le service avec le port 9876, l'application Mac affiche une erreur de connexion refusée lorsque j'essaie de me connecter avec. Alors, comment puis-je trouver un port à utiliser sans utiliser NSSocketPort?

Réponses:

4 pour la réponse № 1

Ok, j'ai regardé le code WiTap d'Apple et l'ai légèrement modifié pour m'écrire une méthode pour obtenir un port:

- (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);
}

}

J'ai enlevé beaucoup de trucs d'erreur donc ce n'est probablement pas optimal, mais ça marche.


4 pour la réponse № 2

Depuis iOS 7, NSNetService peut créer et lier le socket pour vous. S'il est initialisé avec le port zéro, il choisira un port aléatoire:

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

Le service enverra netService:didAcceptConnectionWithInputStream:outputStream: à son délégué lorsqu'une connexion est établie.