我有一些代码曾经工作了很多年,即使现在在特定情况下它也可以工作,但在其他情况下我只是无法理解为什么它会失败。
下面的代码是使用System.Net.Sockets.Socket
进行通信的 Client 类的一部分:
protected ConcurrentQueue<byte[]> ReadQueue { get; } = new ConcurrentQueue<byte[]>();
private void ReadTimer_Tick(object sender, EventArgs e) {
ReadTimer.Stop();
try
{
while (ReadQueue.Count > 0 && !IsDisposing)
{
try
{
if (this.ReadQueue.TryDequeue(out var data))
{
[...]
}
}
catch (Exception ex)
{
[...]
}
}
}
catch (Exception)
{
[...]
}
finally
{
if (IsConnected && !IsDisposing) ReadTimer.Start();
}
}
protected void EnqueueData(IEnumerable<byte> data)
{
ReadQueue.Enqueue(data.ToArray());
}
如果不停止ReadTimer
以处理来自ConcurrentQueue
的数据,则每毫秒滴答一次。
该代码有两种用途:
第一种情况
我打开了与Socket
端口的连接。建立连接后,我调用Socket
的Socket.BeginReceive
方法。
第二种情况
我侦听一个Socket
端口并调用Socket.BeginAccept
方法。在BeginAccept
的"回调"方法中,我还调用Socket
的BeginReceive
方法。
在这两种情况下,调用相同的方法:
private void StartReceiving(SocketAnswerBuffer state)
{
try
{
Status = ClientStatus.Receiving;
_ = state.Socket.BeginReceive(
state.Buffer, 0,
state.Buffer.Length,
SocketFlags.None,
ReceiveCallback,
state
);
}
catch (Exception ex)
{
[...]
}
}
因此,在这两种情况下,ReceiveCallback
都用于处理传入的数据:
private void OnReceive(IAsyncResult result)
{
if (result.AsyncState is SocketAnswerBuffer state)
{
try
{
var size = state.Socket.EndReceive(result);
if (size > 0)
{
var data = state.Buffer.Take(size).ToArray();
EnqueueData(data);
}
}
catch (Exception ex)
{
[...]
}
finally
{
Status = ClientStatus.Connected;
if (state != null && state.Socket.Connected)
StartReceiving(state);
}
}
}
在这两种情况下,都会调用EnqueueData
方法。
在第一种情况下,一切正常。当ReadTimer
时钟周期ReadQueue.Count
大于 0 时,循环将处理到目前为止收集的所有数据并对其进行处理。
在第二种情况下,还会调用EnqueueData
并将数据排队到ReadQueue
。但是当ReadTimer
滴答声ReadQueue.Count
为 0 时,没有任何效果。
我真正无法理解的是,调试代码显示ReadQueue.Count
在EnqueueData
上大于 0,ReadQueue
甚至增长,但ReadTimer_Tick
ReadQueue
仍然是空的......我既不清除也不重新声明ReadQueue
ReadTimer_Tick
是代码中唯一尝试将数据从ReadQueue
中取消排队的方法。
以某种方式创建一个包含Timer
、ConcurrentQueue
和处理数据的方法的新类,并在类中将此类与Socket
一起使用,强制ConcurrentQueue
与Timer
和方法同步。