0

我正在试验 C++ winsockets。我想创建一种方法,在不知道它的 IP 的情况下,我可以在网络上找到服务器。为此,我只需通过 IP 地址 192.168.1.0 到 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;
}

另外,请随时告诉我我在当前连接方法中做错的任何事情。

4

7 回答 7

3

长时间的延迟是由于套接字在返回调用者之前需要超时造成的。为了减少总执行时间,您应该创建多个同时连接到不同 IP 地址的工作线程。

于 2009-02-17T20:42:58.687 回答
3

好的,这里有几件事。

首先,连接被设计为在超时之前等待一段时间,以防服务器繁忙。您可以调整超时长度,尽管我不记得究竟是如何做到这一点的。

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

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

于 2009-02-17T20:48:21.140 回答
1

我会做一个研究,看看winsock是否支持异步I/O。

于 2009-02-17T20:47:41.860 回答
1

服务器 IP 地址是否如此随机,以至于您每次都需要这样做?我很长一段时间没有做过任何套接字编程,但是有超时和这样的情况可能不会变得更好。

其他选项:

  • 使用 IP 地址的网络共享上的配置文件怎么样?这可以在服务器启动时重写。
  • 将服务器的 IP 地址设为静态和硬编码或放入配置文件
  • 通过机器的 DNS 或 NETBIOS 名称查找
于 2009-02-17T20:49:39.980 回答
0

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

于 2009-02-17T21:00:18.163 回答
0

过去,在“每个人都有 139 端口”开放日,我已经成功地做到了这一点。

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

我仍然有源代码(C++),如果您想查看它,请给我留言。

另外,到底为什么需要扫描 IP?即使它是动态的,您也应该能够通过其主机名查找 ip。请参阅 gethostbyname() 或 getaddrinfo()。

于 2009-02-17T21:20:17.850 回答
0

我看到你正在使用窗户。但是,如果您使用的是 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
}
于 2009-02-17T21:49:40.023 回答