简体   繁体   English

顺序访问异步套接字

[英]Sequential access to asynchronous sockets

I have a server that has several clients C1...Cn to each of which there is a TCP connection established. 我有一台服务器,它有几个客户端C1 ... Cn,每个客户端都建立了TCP连接。 There are less than 10,000 clients. 客户不到10,000。

The message protocol is request/response based, where the server sends a request to a client and then the client sends a response. 消息协议是基于请求/响应的,其中服务器向客户端发送请求,然后客户端发送响应。

The server has several threads, T1...Tm, and each of these may send requests to any of the clients. 服务器有几个线程,T1 ... Tm,每个线程都可以向任何客户端发送请求。 I want to make sure that only one of these threads can send a request to a specific client at any one time, while the other threads wanting to send a request to the same client will have to wait. 我想确保这些线程中只有一个可以在任何时候向特定客户端发送请求,而其他想要向同一客户端发送请求的线程则必须等待。

I do not want to block threads from sending requests to different clients at the same time. 我不想阻止线程同时向不同的客户端发送请求。

Eg If T1 is sending a request to C3, another thread T2 should not be able to send anything to C3 until T1 has received its response. 例如,如果T1正在向C3发送请求,则另一个线程T2在T1收到响应之前不应该向C3发送任何内容。

I was thinking of using a simple lock statement on the socket: 我想在套接字上使用一个简单的锁定语句:

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

I am using asynchronous sockets, so I may have to use Monitor instead: 我使用异步套接字,所以我可能不得不使用Monitor:

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

And

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

I am worried about stuff going wrong and not letting go of the monitor and therefore blocking all access to a client. 我担心出错了,不放弃显示器,因此阻止了对客户端的所有访问。 I'm thinking that my heartbeat thread could use Monitor.TryEnter() with a timeout and throw out sockets that it cannot get the monitor for. 我在想我的心跳线程可以使用带有超时的Monitor.TryEnter()并抛出无法获取监视器的套接字。

Would it make sense for me to make the Begin and End calls synchronous in order to be able to use the lock() statement? 为了能够使用lock()语句,让Begin和End调用同步是否有意义? I know that I would be sacrificing concurrency for simplicity in this case, but it may be worth it. 我知道在这种情况下我会牺牲并发性以简化,但它可能是值得的。

Am I overlooking anything here? 我在这里俯瞰什么吗? Any input appreciated. 任何输入赞赏。

My answer here would be a state machine per socket. 我的答案是每个插槽的状态机 The states would be free and busy : 各州将free busy

  • If socket is free , the sender thread would mark it busy and start sending to client and waiting for response. 如果套接字是free ,则发送方线程会将其标记为busy并开始向客户端发送并等待响应。
  • You might want to setup a timeout on that wait just in case a client gets stuck somehow. 您可能希望在该等待时设置超时,以防客户端以某种方式卡住。
  • If the state is busy - the thread sleeps, waiting for signal. 如果状态正busy - 线程休眠,等待信号。
  • When that client-related timeout expires - close the socket, the client is dead. 当与客户端相关的超时到期时 - 关闭套接字,客户端已经死亡。
  • When a response is successfully received/parsed, mark the socket free again and signal/wakeup the waiting threads. 成功接收/解析响应后,再次将套接字标记为free并发出信号/唤醒等待的线程。
  • Only lock around socket state inquiry and manipulation, not the actual network IO. 只锁定套接字状态查询和操作,而不是实际的网络IO。 That means a lock per socket, plus some sort of wait primitive like a conditional variables (sorry, don't remember what's really available in .NET) 这意味着每个套接字一个锁,加上某种类似条件变量的等待原语(抱歉,不记得.NET中真正可用的内容)

Hope this helps. 希望这可以帮助。

You certainly can't use the locking approach that you've described. 你当然不能使用你所描述的锁定方法。 Since your system is primarily asynchronous, you can't know what thread operations will be running on. 由于您的系统主要是异步的,因此您无法知道将运行哪些线程操作。 This means that you may call Exit on the wrong thread (and have a SynchronizationLockException thrown), or some other thread may call Enter and succeed even though that client is "in use", just because it happened to get the same thread that Enter was originally called on. 这意味着您可以在错误的线程上调用Exit(并抛出SynchronizationLockException),或者某个其他线程可以调用Enter并成功,即使该客户端“正在使用”,只是因为它恰好获得了与Enter相同的线程最初打过电话。

I'd agree with Nikolai that you need to hold some additional state alongside each socket to determine whether it is currently in use or not. 我同意尼古拉的说法,你需要在每个插座旁边保留一些额外的状态,以确定它是否正在使用中。 You woud of course need locking to update this shared state. 你当然需要锁定来更新这个共享状态。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM