3

我最初在发送数据时遇到了竞争条件,问题是我允许使用多个 SocketAsyncEventArgs 来发送数据,但是第一个数据包在第二个数据包之前没有完全发送,这是因为我有它所以如果数据缓冲区不适合它循环,直到所有数据都发送完毕,并且第一个数据包比第二个数据包大,第二个数据包很小,所以第二个数据包在第一个数据包之前被发送并到达客户端。

我通过将 1 个 SocketAyncEventArgs 分配给一个用于发送数据的打开连接并使用信号量来限制对它的访问来解决这个问题,并在完成后使 SocketAsyncEventArgs 回调。

现在这工作正常,因为所有数据都已发送,当它完成下一次发送准备好时回调。问题是,当我想将数据随机发送到打开的连接时,它会导致阻塞,而当有大量数据发送时,它会阻塞我的线程。

我正在寻找解决此问题的方法,我想有一个队列,当请求发送数据时,它只是将数据包添加到队列中,然后 1 SocketAsyncEventArgs 只是循环以发送该数据。

但是我怎样才能在保持可扩展性的同时有效地做到这一点呢?在按照请求发送的顺序发送数据包时,我想尽可能避免阻塞。

感谢任何帮助!

4

1 回答 1

4

如果数据需要保持有序,又不想阻塞,那么就需要添加队列。我这样做的方法是在我的状态对象上跟踪我们是否已经有一个正在处理该连接的活动发送异步循环。在入队之后(显然必须同步),只需检查正在进行的内容:

    public void PromptToSend(NetContext context)
    {
        if(Interlocked.CompareExchange(ref writerCount, 1, 0) == 0)
        { // then **we** are the writer
            context.Handler.StartSending(this);
        }
    }

writerCount是连接上的写循环计数(应该正好是 1 或 0);如果没有,我们开始一个。

StartSending尝试从该连接的队列中读取;如果它可以这样做,它会做通常的SendAsync等:

if (!connection.Socket.SendAsync(args)) SendCompleted(args);

(请注意,SendCompleted这里是针对“同步”情况的;对于“异步”情况,它必须SendCompleted通过事件模型)。SendCompleted显然,重复这个“出队,尝试发送异步”步骤。

剩下的唯一事情是确保当我们尝试出队时,如果我们发现没有更多可做的事情,我们会注意到缺乏行动:

        if (bufferedLength == 0)
        {  // nothing to do; report this worker as inactive
            Interlocked.Exchange(ref writerCount, 0);
            return 0;
        }

有道理?

于 2012-07-25T11:35:52.160 回答