Assam AlZookery
Assam AlZookery

Reputation: 479

How to get the IP address in client automatically objective c

I have two Applaction one is the client (IOS device) and the other one is the server (PC device).

I would like to get the ip address in the client (IOS device ) Automatically.

I'm using this line of code to type the IP address

NSString *ipAddressText = @"192.168.211.62";

I don't want to keep typing the Ip address, becuase the IP address will change most of the time.

here's my code

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

Upvotes: 1

Views: 1439

Answers (1)

Richard Stelling
Richard Stelling

Reputation: 25665

This is in Swift, but can easily be dropped into any Xcode project.

NB: This example is taken from a GitHub project Host.swift.

Getting information about network interfaces in Unix type systems like iOS or Mac OS X requires using some arcane C APIs. These APIs have varying amounts of visibility in and , and .

If you're exclusively targeting macOS with Objective-C, then is your best solution. However, if you require iOS compatibility then you'll have to drop down to lower level C API such as getifaddrs(...) or .

If you want a based solution even getifaddrs(...) comes with some bridging header requirements (making it unusable in a Framework).

Here is an example using CFHost and sockaddr_in struct that will work in Swift and on macOS and iOS (even in Frameworks). See Host.swift on GitHib for a fully working example.

  1. Use CFHost to get the addressing info, this will be a CFArray of CFData objets.

    let sockaddrs = CFHostGetAddressing("apple.com", &resolved)?.takeRetainedValue() 
    
  2. Get the first object

    let data = CFArrayGetValueAtIndex(sockaddrs, 0)
    
  3. Cast the bytes into a sockaddr struct

    var storage = sockaddr_storage()
    data.getBytes(&storage, length: sizeof(sockaddr_storage))
    
  4. Then force the sockaddr struct into a sockaddr_in struct so we can use it

    let addr = withUnsafePointer(&storage) { UnsafePointer<sockaddr_in>($0).memory
    
  5. Use the inet_ntoa(...) function to turn addr.sin_addr (IP address) into a C-string. We can then use String(Cstring: encoding:) to get a nice String of the IP Address.

    let address = String(CString: inet_ntoa(addr.sin_addr), encoding: NSUTF8StringEncoding)
    

Here is a GitHub project called Host.swift that I created to solve these issues using the technique above.

Upvotes: 1

Related Questions