TCP-клиент в iOS/Objective-C — проверка открытого порта

Я просмотрел несколько вопросов по SO об AsyncSocket, но ничего не нажал. Я чувствую, что то, что я пытаюсь сделать, довольно просто, так что это будет ладонь... Я пробовал версию без GCD, но это тоже не приносит удовольствия.

Мне нужно иметь возможность сканировать ряд хостов для определенного открытого TCP-порта. К сожалению, у меня нет контроля над кодом сервера, чтобы он объявлял себя с помощью Bonjour. Итак, я приступаю к сканированию грубой силы и просто пытаюсь подключиться к этому одному порту - если я получаю «Отказ в подключении», то я знаю, что нужно двигаться дальше ...

Все это привело меня к AsyncSocket, который я считаю подходящим инструментом для работы. Используя примеры автора, у меня есть базовый рабочий пример, но не совсем. Как и его образцы, я просто использую основную очередь для простоты. Дело в том, что это похоже на дерьмовую стрельбу относительно того, вызывается ли метод делегата. Иногда socketDidDisconnect: срабатывает, иногда нет. В данном конкретном случае я знаю, что порт 5002 открыт на 192.168.1.7. Однако, когда он достигает этого элемента в массиве, didConnectToHost не срабатывает. Однако, если я удалю из списка IP-адресов все, кроме .7, то didConnectToHost сработает. Я подозреваю, что вызов connectToHost: в таком тесном цикле является проблемой, но я не могу это доказать. Если кто-то знает более простой способ сделать это, я открыт для него. Удивительно, но на эту тему не так много.

#import "GCDAsyncSocket.h"

#define PORT 5002

@implementation ViewController
{
    GCDAsyncSocket *asyncSocket;
    NSMutableArray *availableHosts;
}

- (IBAction)startScan
{
    NSArray *ipAddressList = @[@"192.168.1.1",@"192.168.1.2",@"192.168.1.3",@"192.168.1.4",@"192.168.1.5",@"192.168.1.6",@"192.168.1.7"];

    dispatch_queue_t mainQueue = dispatch_get_main_queue();

    asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:mainQueue];
    NSError *error = nil;

    for (int i = 1; i < ipAddressList.count; i++) {
        NSString *scanHostIP = ipAddressList[i];
        [asyncSocket connectToHost:scanHostIP onPort:PORT withTimeout:1 error:&error];
    }
}

- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
    NSLog(@"Found open port %d on %@", port, host);
    [availableBeds addObject:host];
    [sock setDelegate:nil];
    [sock disconnect];
    [sock setDelegate:self];

}

- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
{
    NSLog(@"Disconnected: %@", err ? err : @"");
}

person voodoobilly    schedule 16.02.2014    source источник


Ответы (1)


Я попробовал что-то подобное, где я сначала нашел свой собственный IP-адрес, а затем изменил его, чтобы отобразить весь диапазон подсети. У меня получилось что-то вроде "192.168.10". И тогда я делаю

- (void)startScan:(NSString *)ipRange
{
    dispatch_queue_t mainQueue = dispatch_get_main_queue();

    asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:mainQueue];
    NSError *error = nil;

    for (int i = 1; i < 255; i++) {
        NSString *scanHostIP = [NSString stringWithFormat:@"%@%d", ipRange, i];
        [asyncSocket connectToHost:scanHostIP onPort:PORT error:&error];
    }
    //connect to an IP that listens on the certain port
    [asyncSocket connectToHost:@"192.168.10.162" onPort:PORT error:&error]; 
}

Когда я пытаюсь подключиться к 162 в цикле, метод делегата никогда не вызывается. Но когда я подключаюсь только к этому конкретному IP-адресу, он внезапно вызывается. Интересно, что метод делегата не вызывается, когда я сначала запускаю цикл, а затем пытаюсь подключиться к конкретному хосту.

Я пытался подключиться с тайм-аутом и без него, но это не помогло.

Я проверил метод connectToHost, и он всегда что-то возвращает. Даже если я попытаюсь подключиться к двум IP-адресам, метод делегата не сработает.

Подводя итог моему опыту: кажется, что цикл каким-то образом блокирует метод делегата. Я подозреваю, что он предназначен только для подключения к одному адресу? Тогда это был бы неправильный инструмент для сканирования подсети.

EDIT: я нашел хорошее решение. Для сканирования всей сети я начал использовать следующий код:

-(void)startScan
{
    dispatch_queue_t mainQueue = dispatch_get_main_queue();

    asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:mainQueue];
    NSError *error = nil;

    NSString *scanHostIP = [NSString stringWithFormat:@"%@%d", ipRange, count];
    [asyncSocket connectToHost:scanHostIP onPort:PORT withTimeout:0.01 error:&error];
}

- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
{
    NSError *error;
    if(count < 254)
    {
        count++;
        NSString *scanHostIP = [NSString stringWithFormat:@"%@%d", ipRange, count];
        [asyncSocket connectToHost:scanHostIP onPort:PORT withTimeout:0.01 error:&error];
    }
}

Хитрость заключалась в том, чтобы дождаться истечения времени ожидания сокета, а затем начать новое соединение. Таким образом, вы можете сканировать всю сеть за допустимый интервал времени.

Надеюсь, это поможет вам или кому-то еще.

person user2240499    schedule 08.01.2015
comment
Я так не думаю, получить порт сложнее, чем получить IP-адрес. У тебя было решение? - person famfamfam; 17.10.2018