我正在做一个程序,允许我同时ping大量不同的IP(大约50-70) .

由于多种原因,我还需要将每个数据包的发送延迟1 ms,特别是当一次发送过多的路由器丢失ICMP数据包时,我的数据包丢失了(特别是在发送机器上,这不是接收者) .

所以我在一个单独的线程中做了这样的事情:

// Send thread
for (;;) {
   [...]
   for (int i = 0; i < ip_count; i++)
   {
      // Send() calls sendto()
      Send(m_socket, ip_array[i]);
      [...]
      Sleep(1); // Delay by 1 ms
   }
   [...]
   lock_until_new_send_operation();
}

在另一个线程中,线程我想用select()接收数据包,就像那样

// Receive thread
FD_ZERO(&m_fdset_read);
FD_SET(m_socket, &m_fdset_read);
int rds_count = select(0, &m_fdset_read, 0, 0, &tvtimeout);
if (rds_count > 0)
    ProcessReadySocket(); // Calls recv() and stuff
else {
    // Timed out
    m_bSendGrapeDone = true;
}

这种方法的问题在于,由于对select()和sento()的调用都使用相同的非阻塞套接字m_socket,因此对sendto()的调用稍后会阻塞,因为select()会在同时调用两者时生成sendto()块(由于一些奇怪的原因...在那里看不到这样的逻辑,因为套接字是非阻塞的,但它仍然存在,它的丑陋) .

所以我决定使用一个专门用于发送然后更换线路的套接字

Send(m_socket, ip_array[i]);

Send(m_sendSock, ip_array[i]); // m_sendSock is dedicated to sending only

我在MSDN上读到,对于原始套接字,每个套接字都接收套接字设置的协议的所有数据包(我的是IPPROTO_ICMP ofc) . 在这里我引用:

使用SOCK_RAW类型的套接字的应用程序还有其他限制 . 例如,侦听特定协议的所有应用程序都将接收为此协议接收的所有数据包

所以我想即使我的数据包是用m_sendSock发送的,我仍然可以在m_socket上使用select()/ recv()接收它们,结果我不能,select()永远不会返回套接字是可读的 . 所以我有点卡住,我不能同时使用select()和send() . 有什么我做错了吗?

(顺便说一句,我想使用原始套接字,而不是内置的windows icmp函数)

TL; DR如何同时发送()和select()?因为在发送线程上,只要在接收线程上调用select()就发送send()块,即使我在其上使用了FIONBIO(非阻塞) . 如果我使用两个不同的插座,一个用于发送,一个用于接收,我在接收插座上什么都没有收到...

谢谢!