ConcurrentQueue.Count 在套接字接收添加数据时保持为零



我有一些代码曾经工作了很多年,即使现在在特定情况下它也可以工作,但在其他情况下我只是无法理解为什么它会失败。

下面的代码是使用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端口的连接。建立连接后,我调用SocketSocket.BeginReceive方法。

第二种情况

我侦听一个Socket端口并调用Socket.BeginAccept方法。在BeginAccept的"回调"方法中,我还调用SocketBeginReceive方法。

在这两种情况下,调用相同的方法:

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.CountEnqueueData上大于 0,ReadQueue甚至增长,但ReadTimer_TickReadQueue仍然是空的......我既不清除也不重新声明ReadQueueReadTimer_Tick是代码中唯一尝试将数据从ReadQueue中取消排队的方法。

以某种方式创建一个包含TimerConcurrentQueue和处理数据的方法的新类,并在类中将此类与Socket一起使用,强制ConcurrentQueueTimer和方法同步。