2

我已经研究了关于 AsyncSocket 的一些关于 SO 的问题,但没有点击任何内容。我觉得我正在尝试做的事情相当简单,所以它会是面对面的......我已经尝试过非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 : @"");
}
4

1 回答 1

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 方法,它总是返回一些东西。即使我尝试连接到 2 个 IP,它也不会触发委托方法。

总结一下我的经验:循环似乎以某种方式阻止了委托方法。我怀疑它只是为了连接到一个地址?那么这将是扫描子网的错误工具。

编辑: 我找到了一个不错的解决方案。为了扫描整个网络,我开始使用以下代码:

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

诀窍是等待套接字超时,然后启动新连接。这样,您可以在可容忍的时间间隔内扫描整个网络。

希望这对您或其他人有所帮助。

于 2015-01-08T09:20:54.477 回答