如何自动获取客户端中的IP地址c

时间:2016-05-20 22:22:42

标签: ios objective-c sockets

我有两个Applaction,一个是客户端(IOS设备),另一个是服务器(PC设备)。

我想自动获取客户端(IOS设备)中的IP地址。

我正在使用这行代码输入IP地址

NSString *ipAddressText = @"192.168.211.62";

我不想继续输入IP地址,因为IP地址大部分时间都会改变。

这是我的代码

  -(void)viewDidLoad{
            [super viewDidLoad];


            NSString *ipAddressText = @"192.148.211.42";

            NSLog(@"Setting up connection to %@ : %i", ipAddressText, 111);
            CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (__bridge CFStringRef) ipAddressText, 111, &readStream, &writeStream);
            messages = [[NSMutableArray alloc] init];
            [self open];
        }

    - (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {

        NSLog(@"stream event %lu \n ", streamEvent);

        switch (streamEvent) {

            case NSStreamEventOpenCompleted:
                NSLog(@"Stream opened");
                _connectedLabel.text = @"Connected";
                break;
            case NSStreamEventHasBytesAvailable:

                if (theStream == inputStream)
                {
                    uint8_t buffer[1024];
                    NSInteger len;

                    while ([inputStream hasBytesAvailable])
                    {
                        len = [inputStream read:buffer maxLength:sizeof(buffer)];
                        if (len > 0)
                        {
                            NSString *output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSASCIIStringEncoding];

                            if (nil != output)
                            {
                                NSLog(@"server said: %@ \n ", output);
                                [self messageReceived:output];
                            }
                        }
                    }
                }
                break;

            case NSStreamEventHasSpaceAvailable:
                NSLog(@"Stream has space available now");
                break;

            case NSStreamEventErrorOccurred:
                NSLog(@"%@\n",[theStream streamError].localizedDescription);
                break;

            case NSStreamEventEndEncountered:

                [theStream close];
                [theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
                _connectedLabel.text = @"Disconnected";
                NSLog(@"close stream");
                break;
            default:
                NSLog(@"Unknown event");
        }

    }

        - (void)open {

            NSLog(@"Opening streams.");

            outputStream = (__bridge NSOutputStream *)writeStream;
            inputStream = (__bridge NSInputStream *)readStream;

            [outputStream setDelegate:self];
            [inputStream setDelegate:self];

            [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

            [outputStream open];
            [inputStream open];

             _connectedLabel.text = @"Connected";
        }


    - (void)close {
        NSLog(@"Closing streams.");
        [inputStream close];
        [outputStream close];
        [inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        [outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        [inputStream setDelegate:nil];
        [outputStream setDelegate:nil];
        inputStream = nil;
        outputStream = nil;

        _connectedLabel.text = @"Disconnected";
    }

1 个答案:

答案 0 :(得分:1)

这是在Swift中,但很容易被放入任何Xcode项目中。

注意:此示例来自GitHub项目Host.swift

获取有关Unix类型系统(如iOS或Mac OS X)中的网络接口的信息,需要使用一些神秘的C API。这些API在中具有不同的可见度。

如果您使用Objective-C专门定位macOS,那么是您的最佳解决方案。但是,如果您需要iOS兼容性,那么您必须下拉到较低级别的C API,例如getifaddrs(...)

如果您想要基于的解决方案,即使getifaddrs(...)也会附带一些桥接标头要求(使其在框架中无法使用)。

以下是使用CFHostsockaddr_in struct的示例,它可以在Swift以及macOS和iOS(甚至是Frameworks)中使用。有关完整的示例,请参阅GitHib上的Host.swift

  1. 使用CFHost获取地址信息,这将是CFArrayCFData对象。

    let sockaddrs = CFHostGetAddressing("apple.com", &resolved)?.takeRetainedValue() 
    
  2. 获取第一个对象

    let data = CFArrayGetValueAtIndex(sockaddrs, 0)
    
  3. 将字节转换为sockaddr struct

    var storage = sockaddr_storage()
    data.getBytes(&storage, length: sizeof(sockaddr_storage))
    
  4. 然后强制sockaddr struct加入sockaddr_in struct,以便我们可以使用

    let addr = withUnsafePointer(&storage) { UnsafePointer<sockaddr_in>($0).memory
    
  5. 使用inet_ntoa(...)功能将addr.sin_addr(IP地址)转换为C字符串。然后我们可以使用String(Cstring: encoding:)来获得一个很好的IP地址字符串。

    let address = String(CString: inet_ntoa(addr.sin_addr), encoding: NSUTF8StringEncoding)
    
  6. 这是一个名为Host.swift的GitHub项目,我使用上述技术解决了这些问题。