顺序访问异步套接字

时间:2010-06-11 18:53:27

标签: c# .net sockets concurrency asynchronous

我有一台服务器,它有几个客户端C1 ... Cn,每个客户端都建立了TCP连接。客户不到10,000人。

消息协议基于请求/响应,服务器向客户端发送请求,然后客户端发送响应。

服务器有几个线程,T1 ... Tm,每个线程都可以向任何客户端发送请求。我想确保这些线程中只有一个可以在任何时候向特定客户端发送请求,而其他想要向同一客户端发送请求的线程则必须等待。

我不想阻止线程同时向不同的客户端发送请求。

E.g。如果T1正在向C3发送请求,则另一个线程T2在T1收到响应之前不应该向C3发送任何内容。

我在考虑在套接字上使用一个简单的锁定语句:

lock (c3Socket)
{
    // Send request to C3
    // Get response from C3
}

我正在使用异步套接字,因此我可能不得不使用Monitor:

Monitor.Enter(c3Socket); // Before calling .BeginReceive()

Monitor.Exit(c3Socket); // In .EndReceive

我担心出错了,不放弃显示器,因此阻止了对客户端的所有访问。我认为我的心跳线程可以使用Monitor.TryEnter()超时并抛出无法获取监视器的套接字。

为了能够使用lock()语句,让Begin和End调用同步是否合理?我知道在这种情况下我会牺牲并发性以简化,但它可能是值得的。

我在这里俯瞰什么吗?任何意见都赞赏。

2 个答案:

答案 0 :(得分:2)

我的答案是每个插槽的状态机。状态为freebusy

  • 如果套接字为free,发件人线程会将其标记为busy并开始向客户端发送并等待响应。
  • 您可能希望在等待时设置超时,以防客户端以某种方式卡住。
  • 如果状态为busy - 线程休眠,等待信号。
  • 当与客户端相关的超时到期时 - 关闭套接字,客户端已经死了。
  • 成功接收/解析响应后,再次标记套接字free并发出信号/唤醒等待的线程。
  • 仅锁定套接字状态查询和操作,而不是实际的网络IO。这意味着每个套接字一个锁,加上某种类似条件变量的等待原语(抱歉,不记得.NET中真正可用的那些)

希望这有帮助。

答案 1 :(得分:2)

你当然不能使用你所描述的锁定方法。由于您的系统主要是异步的,因此您无法知道将运行哪些线程操作。这意味着您可以在错误的线程上调用Exit(并抛出SynchronizationLockException),或者某个其他线程可以调用Enter并成功,即使该客户端“正在使用”,只是因为它恰好获得了与Enter相同的线程最初打过电话。

我同意Nikolai的说法,你需要在每个插座旁边保留一些额外的状态,以确定它是否正在使用中。你当然需要锁定来更新这个共享状态。