我正在 Linux 下编写一个 C/C++ 应用程序,它从原始套接字(用于 ICMP 数据包)读取数据。问题:有没有办法丢弃仍在套接字上排队的所有数据?
问题是睡了一会儿后,socket上有我不感兴趣的数据排队;所以最好只是告诉套接字“忘记你现在缓冲的所有数据”,这样如果我进入一个 select()/recvfrom() 循环,我只会得到最近收到的数据。
有没有比先进入单独的 poll()/recvfrom() 循环更好的方法?可能是一些套接字 API 调用?便携,甚至?:-)
我正在 Linux 下编写一个 C/C++ 应用程序,它从原始套接字(用于 ICMP 数据包)读取数据。问题:有没有办法丢弃仍在套接字上排队的所有数据?
问题是睡了一会儿后,socket上有我不感兴趣的数据排队;所以最好只是告诉套接字“忘记你现在缓冲的所有数据”,这样如果我进入一个 select()/recvfrom() 循环,我只会得到最近收到的数据。
有没有比先进入单独的 poll()/recvfrom() 循环更好的方法?可能是一些套接字 API 调用?便携,甚至?:-)
在空闲时间,您可以通过将接收缓冲区大小设置为零来禁用套接字:
int optval = 0; /* May need to be 1 on some platforms */
setsockopt(sockDesc, SOL_SOCKET, SO_RCVBUF, (char *)(&optval), sizeof(optval));
通过将“optval”设置为更大的缓冲区(例如 4096)重新启用。
我建议不要睡觉。使用 select 调用在数据到达时立即处理数据。
while (1)
{
FD_ZERO (&sockets);
FD_SET (raw_socket, &sockets);
timeout.tv_sec = 1;
timeout.tv_usec = 0;
if (select (raw_socket + 1, &sockets, NULL, NULL, &timeout))
{
if (FD_ISSET (raw_socket, &sockets))
{
// handle the packet
}
}
else
{
/* Select Timed Out */
fprintf(stderr, "Timed out");
}
}
此外,在创建原始套接字时,您可以指定您只对 icmp 数据包感兴趣。
我知道如何可靠地做到这一点的唯一方法是关闭套接字。
你不能只做recvfrom()
一个临时缓冲区并丢弃缓冲区吗?
我没有尝试过,出于性能原因,这可能是完全不明智的(但如果您的应用程序无论如何都处于睡眠状态,这可能不是问题),但是:您可以尝试在睡眠之前将套接字的接收缓冲区设置为一些非常小的值。我希望这会导致套接字无法缓冲应用程序未侦听时到达的数据。这是一个很长的镜头。
或者,也许在睡眠后重置接收缓冲区大小,当您准备再次开始阅读时,也会导致它刷新它。当然,这些技巧仅此而已,即使它们有效,它们也肯定是不可移植的。我只是想我会分享这个想法,如果您有机会对其进行测试,它可能会对您有所帮助。
你能在睡前做这样的事吗?
for(n=0;n<=MAX_BUFFER_SIZE;n++)
{
recv_buffer[n] = 0;
}
中间件应用程序中的标准过程是有一个专用线程来服务 IO 请求,其优先级设置为高于其他应用程序线程。当 IO 线程接收到一个数据包时,它会将其排入应用层。当应用程序有空闲时间时,它会将下一个数据包出列。
这是 TIBCO Rendezvous 背后的架构,用于许多实时市场数据和企业消息传递系统。需要注意的是,您通常希望对队列大小进行一些限制,这样应用程序就不会被 OOM 管理器获取。IO 线程和应用层之间的协议可以从简单的异步队列到更复杂的主题过滤、优先级列表以及支持线程池以并行解码传入数据。