【问题标题】:Manage timeouts for multiple UDP sockets管理多个 UDP 套接字的超时
【发布时间】:2011-11-23 22:05:51
【问题描述】:

我必须在 Windows 和 Linux 上为大学课程编写 TFTP(普通文件传输协议)服务器。我正在使用 C++,我想使用一个线程和 select() 来检查新的传入数据包。 TFTP 要求如果数据包在一定时间内没有被确认,则重新发送数据包。我想知道管理这些多次超时的最佳方法是什么。

我正在考虑创建一个 std::list,其中包含将连接与发生超时的绝对时间相关联的对象。该列表通过增加超时时间来排序(所有超时在分配时都是相同的,因此新的超时始终是最大的,并且可以到列表的末尾 - 否则我需要一个映射而不是列表)。 由于我需要重置连接的超时,如果数据包及时到达,我想创建一个 std::map ,将连接与指向其在列表中的位置的迭代器相关联。当连接的超时更新时,列表中的元素可以快速找到、更新并移动到列表的末尾(再次假设新的超时是最大的)。

这是解决问题的好方法还是有更简单的方法?

【问题讨论】:

  • 请注意不要让迭代器指向您要修改的列表。在这种情况下,将一个项目移动到列表的末尾将使地图持有的迭代器无效。
  • 谢谢你们的帮助。实际上只有被移动项目的迭代器是无效的。其他的仍然有效。见http://www.sgi.com/tech/stl/List.html。但我将使用这个版本,我将项目保存在一个集合中,就像你建议的那样,而不是一个列表(见下面我的评论)。

标签: c++ sockets timeout udp


【解决方案1】:

如果我理解正确,您有成对的连接/超时,并且您希望能够通过连接和超时访问这些对。 通过连接是因为您必须在收到数据包时更改超时,而通过超时是因为您需要知道下一个连接是什么才能超时。

如果您对 boost 没有任何意见,请查看 multi_index

如果你想自己滚动,你可以保留两组指针,给集合不同的比较函数:

class Connection {
    ...
public:
    int GetTimeout() const;
    int GetID() const;
};

class TimeIsLess {
public:
    bool operator()(const Connection*c1, const Connection*c2) const {
        return c1->GetTimeout() < c2->GetTimeout();
    }
}
class IdIsLess {
public:
    bool operator()(const Connection*c1, const Connection*c2) const {
        return c1->GetId() < c2->GetId();
    }
}

std::set<Connection*,TimeIsLess> connectionsByTime;
std::set<Connection*,IdIsLess> connectionsById;

创建连接:

...
Connection * c = new Connection(id, timeout);
connectionsByTime.insert(c);
connectionsById.insert(c);
...

要获取下一个将超时的连接,只需获取第一个:

auto nextToTimeout = connectionsByTime.begin();
if (nextToTimeout != connectionsByTime.end())
{
    if ( (*nextToTimeout)->GetTimeout() < now )
    {
        // Close the connection
    }
}

要删除连接,您必须从一组中删除指针,然后从另一组中删除并删除指针。

我没有编译它,所以不要把错别字钉在我身上(:

【讨论】:

  • 谢谢。这就是我要做的。实际上必须做一个修改版本,它使用一个地图和一个集合。我想编写一个通用类,它也可以用于其他超时。因此,我将创建一个名为 TimeoutKeeper 的类,它将对象与其超时相关联。所以我的两个集合将是一个 map *>,就像你建议的一个 set *>。再次感谢您的帮助。
  • @tommazzo 很高兴为您提供帮助(:嘿,也许您想将家务封装在一个类中,该类将包含(并隐藏)地图和集合。它可以有一个 AddConnection() 、GetConnectionByTime()、GetConnectionByID() 和 RemoveConnection()。我还想在 Get...() 和 Find 之间做出区别,它搜索给定对象的内部结构,如果找不到则添加它。 ..() 仅搜索给定对象并在未找到时返回 NULL 或错误代码。干杯!
  • 当然,我将所有这些都封装在一个单独的类中。事实上,我想在同一个程序的另一个场景中重新使用它,我必须管理缓存中文件映射的超时(这些方法将有一个通用名称,例如 addElement())。谢谢,再次感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 2012-11-12
  • 2022-11-05
  • 1970-01-01
  • 1970-01-01
  • 2011-07-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多