如何在c ++中进行网络ip扫描?

时间:2009-02-17 20:36:40

标签: c++ winsockets

我正在尝试使用C ++ winsockets。我想创建一种方法,我可以在网络上找到服务器,而不知道它的IP。为此,我只需通过IP地址192.168.1.0将我的connect方法循环到192.168.1.255。但是,每次连接之间的时间非常长,程序往往会在:connect(nBytes,(sockaddr *)& server,sizeof(server))语句中等待至少30秒(如果不是更长时间)。我的问题如下:为什么会发生这种情况,我该如何解决这个问题?是否有完全不同的,更好的方法来查找服务器?

我的连接方法:

SOCKET connect(char *ipAdress)
{
WSAData wsaData;

if ((WSAStartup(MAKEWORD(2, 2), &wsaData)) == SOCKET_ERROR)
    return errorReport("Could not create startup struct");

nBytes = socket(AF_INET, SOCK_STREAM, 0);

if (nBytes == SOCKET_ERROR)
    return errorReport("Socket could not be created");

struct hostent *host_entry;

if ((host_entry = gethostbyname(ipAdress)) == NULL)
    return errorReport("Cannot find server.");

struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(1337);
server.sin_addr.s_addr = *(unsigned long*) host_entry->h_addr;

if (connect(nBytes, (sockaddr*)&server, sizeof(server)) == SOCKET_ERROR)
{
    WSACleanup();
    return errorReport("Failed to connect to server.");
}

if (nBytes == -1)
{
    WSACleanup();
    disconnect(nBytes); 
    return errorReport("Could not connect");
}

return 0;
}

另外,请随时告诉我在当前的连接方法中我做错了什么。

7 个答案:

答案 0 :(得分:3)

长时间延迟是由套接字在返回呼叫者之前需要超时引起的。要减少总执行时间,您应该使多个工作线程同时连接到不同的IP地址。

答案 1 :(得分:3)

好的,这里有几件事。

首先,连接设计为在服务器繁忙时超时之前等待一点。你可以调整超时长度,虽然我不记得究竟如何做到这一点。

其次,您的代码会找到一个服务器,但您怎么知道它是您正在寻找的服务器?它可能是一些其他应用程序只是在同一个端口上侦听。除非您只是对任何服务器进行扫描,否则您需要进行一些验证以确定您在另一端与谁通话。

最后,假设您正在编写客户端和服务器,更好的解决方案是让客户端发送广播/多播消息并让服务器(或服务器,如果有多个)监听并响应对那条消息。然后,客户端只需等待一段指定的时间来响应,以确定服务器的位置。

答案 2 :(得分:1)

我会研究一下winsock是否支持异步I / O.

答案 3 :(得分:1)

服务器IP地址是如此随机,您每次都需要这样做吗?我没有在很长一段时间内完成任何套接字编程,但是如果超时,这样可能不会好多了。

其他选择:

  • 网络上的配置文件与IP地址共享怎么样?只要服务器启动,就可以重写。
  • 使服务器的IP地址成为静态和硬编码或放入配置文件
  • 通过机器的DNS或NETBIOS名称查找

答案 4 :(得分:0)

如果您知道服务器在子网上,为什么不发送带有本地接收端口号的广播消息作为消息数据?然后,服务器可以简单地监听此消息并连接回该端口,或将其自己的配置数据发送回该端口,以便客户端可以直接连接。这样,您只需要发送一条消息而不是循环超过256个IP地址。

答案 5 :(得分:0)

过去我在“每个人都有139个开放日”的回归中取得了巨大的成功。

我发现使用多个线程(可悲的是,我使用了大约500个,但这只是一次性拍摄而且只是为了好玩)我在尝试连接之前ping了服务器,允许我每秒遍历几个IP和IP。

我还有源代码(C ++),如果您想查看它,只留下一条消息。

另外,为什么有必要扫描IP?即使它是动态的,你也应该能够通过它的主机名来查看ip。请参阅gethostbyname()或getaddrinfo()。

答案 6 :(得分:0)

我看到你正在使用Windows。但是如果你使用Linux,你可以通过组合非阻塞套接字并选择:

来创建一个超时的连接函数。
int connect_with_timeout(int sock, struct sockaddr *addr, int size_addr, int timeout) {
#if defined(Linux)
    int             error = 0;
    fd_set          rset;
    fd_set          wset;
    int             n;

    // set the socket as nonblocking IO
    int flags = fcntl (sock, F_GETFL, 0);
    fcntl(sock, F_SETFL, flags | O_NONBLOCK);

    errno = 0;

    // we connect, but it will return soon
    n = connect(sock, addr, size_addr);

    if(n < 0) { 
        if (errno != EINPROGRESS) {
            return -1;
        }
    } else if (n == 0) {
        goto done;
    }

    FD_ZERO(&rset);
    FD_ZERO(&wset);
    FD_SET(sock, &rset);
    FD_SET(sock, &wset);

    struct timeval tval;
    tval.tv_sec = timeout;
    tval.tv_usec = 0;

    // We "select()" until connect() returns its result or timeout
    n = select(sock + 1, &rset, &wset, 0, timeout ? &tval : 0);
    if(n == 0) {    
        errno = ETIMEDOUT;
        return -1;
    }

    if (FD_ISSET(sock, &rset) || FD_ISSET(sock, &wset)) {
        socklen_t len = sizeof(error);
        if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
            return -1;
        }
    } else {
        return -1;
    }

done:
    // We change the socket options back to blocking IO
    if (fcntl(sock, F_SETFL, flags) == -1) {
        return -1;
    }
    return 0;
#else
    return connect(sock, addr, size_addr);
#endif
}