我正在做一个程序,允许我同时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()时,send()会生成块。同时调用(由于一些奇怪的原因......在那里看不到这样的逻辑,因为socket是非阻塞的,但它仍然存在,它的丑陋)。
所以我决定使用一个专门用于发送然后替换行
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。例如,所有应用程序都在监听特定的 protocol将接收为此协议接收的所有数据包
所以我想即使我的数据包是用m_sendSock发送的,我仍然可以在m_socket上使用select()/ recv()接收它们,结果我不能,select()永远不会返回套接字是可读的。所以我有点卡住,我不能同时使用select()和send()。有什么我做错了吗?
(顺便说一句,我想使用原始套接字,而不是内置的windows icmp函数)
TL; DR如何同时发送()和选择()?因为在发送线程上,只要在接收线程上调用select()就发送send()块,即使我在其上使用了FIONBIO(非阻塞)。如果我使用两个不同的插座,一个用于发送,一个用于接收,我在接收插座上什么都没有收到......
谢谢!