【问题标题】:Get peer IP address and port on OSX in objective-c from NSStream, CFStream or Socket在 OSX 上从 NSStream、CFStream 或 Socket 获取对等 IP 地址和端口
【发布时间】:2013-11-18 14:32:11
【问题描述】:

我编写了一个服务器,它在特定端口上侦听传入的 tcp 连接。为了管理网络连接,我使用了 Streams (CFStream/NSStream)。建立连接后,我将有关此连接的所有信息保存在专用类的另一个实例中,该专用类也设置为流的委托。

现在我想获取通过已经建立的流向我发送消息的设备的公共 IP,换句话说,我想存储流的对等方的 IP。我尝试了很多东西,但不幸的是我只得到了空值。

是否有可能从所描述形式的现有流中获取对等方的地址(ip 和端口)?

这是我尝试过的一些代码:

CFDataRef peerAddress = CFSocketCopyPeerAddress(_sockRef);
// _sockRef is saved when connection is established in listening callback and is not null

我也尝试在监听回调方法中直接获取信息:

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 :-(

我尝试了另一种方法:

_publicIP = CFWriteStreamCopyProperty((__bridge CFWriteStreamRef)(_writeStream), kCFStreamPropertySocketRemoteHostName);

为什么我总是得到空值?谁能帮帮我?

提前谢谢你!

【问题讨论】:

    标签: ios objective-c sockets core-foundation


    【解决方案1】:

    好的,我现在想通了。这就是我所做的:

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

    之后,您将在 _publicIP 属性中获得公共 IP,在 _publicPort 属性中获得公共端口。所有信息都是从服务器端的连接收集的。

    我希望这篇文章对某人有所帮助 =)

    【讨论】:

    • 看起来内存泄漏,malloc 没有被释放,代码不是真正的线程安全。我将 IPv4 部分更改为:char ipstr[INET_ADDRSTRLEN]; struct in_addr *ipv4addr = &socketaddress->sin_addr; if (inet_ntop(AF_INET, ipv4addr, ipstr, INET_ADDRSTRLEN)) { // convert port to int int portnumber = socketaddress->sin_port; // Save in properties _publicIP = [NSString stringWithFormat:@"%s", ipstr]; _publicPort = [NSString stringWithFormat:@"%d", portnumber]; }
    猜你喜欢
    • 1970-01-01
    • 2017-10-21
    • 1970-01-01
    • 2014-12-29
    • 1970-01-01
    • 2011-10-14
    • 1970-01-01
    • 2017-07-28
    • 1970-01-01
    相关资源
    最近更新 更多