I have some code that used to work for many years and even now in specific cases it works but in other cases I just cannot understand why it fails.
The following code is part of a Client class that uses a System.Net.Sockets.Socket for communication:
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());
}
The ReadTimer ticks every millisecond if it is not stopped in order to process data from the ConcurrentQueue.
There are two uses of the code:
First case
I open a connection to a Socket port. After the connection is established I call the Socket.BeginReceive method of the Socket.
Second case
I listen to a Socket port and call the Socket.BeginAccept method. Within the ´callback´ method of BeginAccept I also call the BeginReceive method of the Socket.
In both cases the same method is called:
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)
{
[...]
}
}
So in both cases the ReceiveCallback is used to handle incoming data:
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);
}
}
}
In both cases the EnqueueData method is called.
In the first case everything works. When the ReadTimer ticks ReadQueue.Count is more than 0 and the loop handles all data collected so far and processes it.
In the second case EnqueueData is also called and enqueues data to the ReadQueue. But when the ReadTimer ticks ReadQueue.Count is 0 and nothing works.
What I really cannot understand is that debugging the code shows that ReadQueue.Count is larger than 0 on EnqueueData and the ReadQueue even grows but in ReadTimer_Tick the ReadQueue remains empty ... I neither clear nor redeclare ReadQueue and ReadTimer_Tick is the only method in code that tries to dequeue the data from ReadQueue.
Somehow creating a new class that includes the
Timer, theConcurrentQueueand the method that proceeds the data and using this class inside the class with theSocketforced theConcurrentQueueto be in sync with theTimerand the method.