Получите одноранговый IP-адрес и порт на OSX в target-c от NSStream, CFStream или Socket

Я написал сервер, который прослушивает определенный порт для входящих соединений TCP. Для управления сетевым подключением я использую потоки (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);

Почему я всегда получаю нулевые значения? Может кто-нибудь мне помочь?

Заранее спасибо!

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

После этого у вас будет публичный IP в собственности _publicIP и общественный порт в собственности _publicPort, Вся информация собирается из соединения на стороне сервера.

Надеюсь этот пост кому-нибудь поможет =)

Другие вопросы по тегам