我最初在发送数据时遇到了竞争条件,问题是我允许使用多个SocketAsyncEventArgs来发送数据,但第一个数据包在第二个数据包之前没有完全发送,这是因为我有它所以如果数据不适合缓冲区,则它会循环,直到发送完所有数据,并且第一个数据包大于第二个数据包,这个数据包很小,因此第二个数据包正在发送并在第一个数据包之前到达客户端。
我通过将1个SocketAyncEventArgs分配给用于发送数据的开放连接并使用信号量来限制对它的访问来解决这个问题,并在完成后使SocketAsyncEventArgs回调。
现在这样可以正常运行,因为所有数据都已发送,当它完全准备好下一次发送时回调。这个问题是,当我想将数据随机发送到开放连接时,它会导致阻塞,并且当有大量数据发送时它会阻塞我的线程。
我正在寻找一个解决这个问题的工作,我想到了一个Queue,当请求发送数据时,它只是将数据包添加到Queue,然后1个SocketAsyncEventArgs只是循环发送该数据。
但是,如何在保持可扩展性的同时有效地做到这一点?我希望尽可能避免阻塞,同时按照请求发送的顺序发送数据包。
感谢任何帮助!
答案 0 :(得分: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
这里是针对“sync”的情况;它可以通过“async”情况的事件模型获得SendCompleted
。 SendCompleted
显然重复这个“出队,尝试发送异步”的步骤。
唯一剩下的就是确保当我们尝试出列时,如果我们找不到任何其他事情,我们会注意到缺少行动:
if (bufferedLength == 0)
{ // nothing to do; report this worker as inactive
Interlocked.Exchange(ref writerCount, 0);
return 0;
}
有意义吗?