.Net套接字(UDP)发送,接收和调度

时间:2016-01-02 19:53:13

标签: c# sockets udp

我目前正在进行个人项目以进行学习。我希望通过UDP建立连接,用于游戏等应用程序。发送的每个数据报都有一个特定的标题,指示哪个"逻辑"它所属的通道 - 例如,通道0就像具有额外标头开销的UDP,而通道1使用更多标头来带来一些额外的可靠性。渠道目标是自动"将消息分成逻辑组,最多可达到特定数量。

在我当前的代码中,在一个处理发送和接收的单独线程中有一个简单的循环:

// This is pseudo code
public void Tick() {
    if(Socket.Poll) {
        do {
            ReadMessage();
        } while(Socket.Available > 0)
    }

    SendQueuedOutgoingMessages();
}

虽然这适用于一个理想的世界,但我有这种感觉,当有太多的传入或传出消息时,这个逻辑会失败。是否可以使用相同的套接字同时发送和接收消息(即发送和接收是异步的还是在不同的线程中)?即使有可能,如果我只使用两个或更多UDP套接字(或混合使用TCP和UDP套接字,如果我需要可靠性),是否会考虑特殊的可维护性?

我可以考虑的最直接的替代方法是使用调度算法来控制通过队列大小或其他因素读取和发送的消息数量,但在这种情况下这会感觉很差且不灵活。

编辑:添加有关代码的更多信息。

如果Tick()方法立即返回,则将其设置为每秒调用一次特定的次数。例如,如果不存在新的输入或输出消息,则每秒30次,如果需要一些时间来发送或接收数据,则更少。我使用了阻塞ReceiveFrom和SendTo方法,以避免繁忙的等待或Sleep(0)等呼叫。

虽然我立即处理传入的消息,但我使用传出消息队列来帮助解决频道问题 - 每个频道都有自己的优先级,直到“没有优先级”,影响其带宽分配随着时间的推移顺利进行忙碌的时刻。

2 个答案:

答案 0 :(得分:1)

是否使用2个插座单独接收和发送,或者只使用一个插座取决于具体情况。如果要发送大量消息,即使您在专用线程上,如果套接字使用的传出队列变满,则套接字可能会阻塞。

这个问题有几种解决方案。使用2个套接字和2个不同的线程就是其中之一,将select与异步套接字结合使用是另一个。关键是你不想因为发送可能会阻止而停止接收。

这些可能的解决方案中的每一个都有其复杂性。

select api用于检查某个套接字是否有接收内容,但您也可以使用它来检测套接字是否可以再次写入。您需要一个套接字选项来将套接字置于非阻塞状态,并且您需要检查每次发送的E_WOULDBLOCK返回码。如果是,则发送失败,您必须自己排队。

你不是真的同时发送和接收,它是顺序的。您可以使用select通过使用使用fd_set api操作的2位掩码来检查套接字是否可写且可读。您可以一次在多个套接字上使用select。然后,如果select(阻塞调用)返回,则可以检查每个位以检查需要执行的操作。

如果套接字没有处于非阻塞状态,发送可以阻塞的原因是套接字的输出队列可能已满。如果套接字阻塞,它只会等待队列再次准备就绪。但在等待期间,您无法在同一个套接字上收到任何内容。这就是为什么你需要非阻塞套接字和select api,结合自己的某种排队机制的原因。

答案 1 :(得分:0)

为什么不简单地标准读取循环设置?

while (true)
    ReadMessage();

不需要安排或限制。没有必要知道数据包是否准备就绪。

您可以在同一个UDP套接字上同时读写。

也不需要传出队列。只需发送。