问题
I have written a server that listens on a specific port for incoming tcp connections. To manage the network connectivity I am using Streams (CFStream/NSStream). When a connection is esthablished I save all the information about this very connection in another instance of a dedicated class which is also set as the delegate for the streams.
Now I want to get the public IP of the device that sends me a message through the already esthablished streams, in other words, I would like to store the IP of the stream's peer. I tried many things, but unfortunately I only get null-values.
Is there a possibility to get the peer's address (ip and port) from an existing stream of the described form?
Here is some code I have tried:
CFDataRef peerAddress = CFSocketCopyPeerAddress(_sockRef);
// _sockRef is saved when connection is established in listening callback and is not null
I also tried to get the information direct in the listening callback method:
NSData *peer = nil;
CFSocketNativeHandle nativeSocketHandle = *(CFSocketNativeHandle *)data;
struct sockaddr *addressinfo = NULL;
uint8_t name[SOCK_MAXADDRLEN];
socklen_t namelen = sizeof(addressinfo);
int result = getpeername(nativeSocketHandle, addressinfo, &namelen);
if (result == 0) {
peer = [NSData dataWithBytes:name length:namelen];
}
struct sockaddr_in *s = (struct sockaddr_in*)name;
char *ipstr = malloc(INET_ADDRSTRLEN);
ipstr = inet_ntoa(s->sin_addr); // is 0.0.0.0 :-(
And I tried another method:
_publicIP = CFWriteStreamCopyProperty((__bridge CFWriteStreamRef)(_writeStream), kCFStreamPropertySocketRemoteHostName);
Why do I always get null-values? Can anyone help me?
Thank you in advance!
回答1:
Okay I figured it out by now. This is what I did:
- (void)getPublicClientAddress {
// Get public IP from stream
// Get hands on appropriate data structures via the socket number
CFSocketNativeHandle nativeSocketHandle = _socketnumber;
uint8_t name[SOCK_MAXADDRLEN];
socklen_t namelen = sizeof(name);
NSData *peer = nil;
if (0 == getpeername(nativeSocketHandle, (struct sockaddr *)name, &namelen)) {
peer = [NSData dataWithBytes:name length:namelen];
}
if (_ipv6){
// If ipv6 is used
struct sockaddr_in6 *socketaddress = (struct sockaddr_in6*)name;
// convert ip to string
char *ipstr = malloc(INET6_ADDRSTRLEN);
struct in6_addr *ipv6addr = &socketaddress->sin6_addr;
inet_ntop(AF_INET6, ipv6addr, ipstr, sizeof(ipstr));
// convert port to int
int portnumber = socketaddress->sin6_port;
// Save in properties
_publicIP = [NSString stringWithFormat:@"%s", ipstr];
_publicPort = [NSString stringWithFormat:@"%d", portnumber];
} else {
// If ipv4 is used
struct sockaddr_in *socketaddress = (struct sockaddr_in*)name;
// convert ip to string
char *ipstr = malloc(INET_ADDRSTRLEN);
struct in_addr *ipv4addr = &socketaddress->sin_addr;
ipstr = inet_ntoa(*ipv4addr);
//inet_ntop(AF_INET, ipv4addr, ipstr, sizeof(ipstr));
// convert port to int
int portnumber = socketaddress->sin_port;
// Save in properties
_publicIP = [NSString stringWithFormat:@"%s", ipstr];
_publicPort = [NSString stringWithFormat:@"%d", portnumber];
}
}
Afterwards you will have the public IP in the property _publicIP
and the public port in the property _publicPort
. All information is gathered from a connection on the server side.
I hope this post will help someone =)
来源:https://stackoverflow.com/questions/20050274/get-peer-ip-address-and-port-on-osx-in-objective-c-from-nsstream-cfstream-or-so