C++ 最佳及;快速查找ip地址是否可访问的方法

C++ 最佳及;快速查找ip地址是否可访问的方法,c++,windows,ip-address,C++,Windows,Ip Address,我需要最快的方法来查看是否可以访问ip地址。在每个ip地址上都有一个服务器在侦听特定端口,因此如果您的方法即将查找服务器是否在侦听端口,请告诉我 原因是,假设我有10个ip地址,其中10个服务器在每个ip地址的端口101上侦听。我希望我的客户能够找到一个可访问的ip地址,并尽可能快地连接到该地址(我不希望他等待30秒以确定ip地址是否可访问,然后尝试列表中的下一个ip地址) 可能必须同时在踏板上进行 尝试从中使用connect()函数打开套接字。它尽可能快,如果端口未打开,它将不会响应SYN数据

我需要最快的方法来查看是否可以访问ip地址。在每个ip地址上都有一个服务器在侦听特定端口,因此如果您的方法即将查找服务器是否在侦听端口,请告诉我

原因是,假设我有10个ip地址,其中10个服务器在每个ip地址的端口101上侦听。我希望我的客户能够找到一个可访问的ip地址,并尽可能快地连接到该地址(我不希望他等待30秒以确定ip地址是否可访问,然后尝试列表中的下一个ip地址)


可能必须同时在踏板上进行

尝试从中使用connect()函数打开套接字。它尽可能快,如果端口未打开,它将不会响应SYN数据包

正如您所意识到的,关键问题是占用一个线程,该线程必须等待SYN-ACK才能执行任何其他操作幸运的是,您不需要线程来;然而,编程异步操作可能很微妙;因此,我建议在并行调度TCP/IP连接操作时使用。。。由于内核正在执行繁重的任务,因此只需一个线程就可以完成。根据您的网络硬件,您可以使用libevent每秒进行100次或数千次连接


另一个选择是哪个更复杂。但是,既然你正在使用C++,你可能会更好。

尝试使用一个连接函数打开一个套接字。它尽可能快,如果端口未打开,它将不会响应SYN数据包

正如您所意识到的,关键问题是占用一个线程,该线程必须等待SYN-ACK才能执行任何其他操作幸运的是,您不需要线程来;然而,编程异步操作可能很微妙;因此,我建议在并行调度TCP/IP连接操作时使用。。。由于内核正在执行繁重的任务,因此只需一个线程就可以完成。根据您的网络硬件,您可以使用libevent每秒进行100次或数千次连接


另一个选择是哪个更复杂。但是由于你使用C++可能会更好地适应你的情况。

通常随机尝试连接一个短的时间就足够了。 可达性不是很重要,从您到服务器的路由存在这一事实并不重要,您是否可以连接到所述服务器才重要。通常,您自己的代码运行速度与您可以设计的任何其他可达性方法一样快

如果你有太长时间的问题,那么试着调整你的回答的长度,或者有更紧的超时时间

简单算法:

shuffle IP addresses
foreach IP in addresses
    attempt connect
    if succeed then
       break

通常,在短时间内随机尝试连接就足够了

可达性不是很重要,从您到服务器的路由存在这一事实并不重要,您是否可以连接到所述服务器才重要。通常,您自己的代码运行速度与您可以设计的任何其他可达性方法一样快

如果你有太长时间的问题,那么试着调整你的回答的长度,或者有更紧的超时时间

简单算法:

shuffle IP addresses
foreach IP in addresses
    attempt connect
    if succeed then
       break

虽然您可以快速确定IP是可访问的,但您的问题是确定IP是不可访问的。原因是您不能总是确定IP不可访问。虽然在某些情况下,您会收到IP不可访问的肯定通知,但通常您的代码不会听到答案,等待一段时间后,您的代码将假定IP不可访问

决定超时的问题是网络拓扑。如果您有一个大的拓扑结构(如Internet),那么如果您试图连接到一个“很远”的IP,您将需要一个大的超时来处理潜在的高延迟


根据您的描述,最好是尝试同时连接到所有服务器,并使用第一个接受连接的服务器。您可以使用线程,也可以使用非阻塞套接字。在非阻塞连接中,连接调用会立即返回,然后您可以使用来有效地确定连接调用何时完成(成功或出现错误)。

虽然您可以快速确定某个IP是可访问的,但您的问题是确定某个IP是不可访问的。原因是您不能总是确定IP不可访问。虽然在某些情况下,您会收到IP不可访问的肯定通知,但通常您的代码不会听到答案,等待一段时间后,您的代码将假定IP不可访问

决定超时的问题是网络拓扑。如果您有一个大的拓扑结构(如Internet),那么如果您试图连接到一个“很远”的IP,您将需要一个大的超时来处理潜在的高延迟


根据您的描述,最好是尝试同时连接到所有服务器,并使用第一个接受连接的服务器。您可以使用线程,也可以使用非阻塞套接字。在非阻塞连接中,连接调用会立即返回,然后您可以使用来有效地确定连接调用何时完成(成功或出现错误)。

下面是可用于同时创建传出连接的代码

在IP上迭代,并在循环中生成传出的连接。
每个连接
conn\u t*
都作为LParam发布在窗口消息中-同时发布

您应该监视消息并仅将第一个连接保存在某个位置-忽略(删除)其他连接

#define MSG_NEW_CONNECTION  (WM_USER + 1)

struct conn_t {
    SOCKET       s;
    sockaddr_in  server;
};

static
UINT OutgoingWorker(LPVOID param)
{
  // `param` holds "conn_t*"
  assert(param);
  if (!param) return 0;
  conn_t* c = (conn_t*)param;
  if (SOCKET_ERROR == connect(c->s, (SOCKADDR*)&c->server, sizeof c->server)) {
    closesocket(c->s);
    return 0;
  }
  PostMessage(mainwnd, MSG_NEW_CONNECTION, 0, (LPARAM)c); // <-- mainwnd handle
  return 0;
}

conn_t*
SpawnOutgoing(const char* dest_ip, const USHORT dest_port)
{
  if (!dest_ip) return NULL;
  SOCKET  s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (INVALID_SOCKET == s) {
    return NULL;
  }
  conn_t* c = new conn_t;
  // Create the socket here but connect it in the worker
  memset(&c->server, 0, sizeof sockaddr_in);
  c->server.sin_family = AF_INET;
  c->server.sin_addr.s_addr = inet_addr(dest_ip);
  c->server.sin_port = htons(dest_port);
  c->s = s;

  CreateThread(0, 0, OutgoingWorker, c);
  return c;
}
#定义消息新连接(WM_用户+1)
结构连接{
插座;
服务器中的sockaddr_;
};