Packet reliability multithread bugs - c#

Ok I need some help. When a packet is sent out that requires reliability it gets passed to the ReliabilityLayer. From there the ReliabilityLayer adds that packet to a list then writes it once to the SocketLayer. The ReliabilityLayer then spawns a thread that has 2 timers. While the packet is still in the list the first timer continuously sends the packet to the SocketLayer every 250ms. The second timer is the timeout time. It throws an exception after 2s. The ReliabilityLayer hooks into the packet receive event and when an ACK packet comes back containing the checksum of a packet in the ReliabilityLayer packet list, it should remove it allowing the thread to exit. Problem is multithreading...Accessing the list across threads is giving me random null pointers and other problems. So I have to either make it thread safe somehow or rethink this whole thing. I was wondering if anyone could help me out? Thanks
public void Write(NetworkPacket packet, ClientInfo client, Action<byte[], EndPoint> action)
{
if (CSL)
throw new Exception("ReliabilityLayer loaded for client use.");
if (!packet.Command.RequiresReliability())
throw new ArgumentException("Packet does not require reliability.");
//Add the packet to the reliability list
packetList.Add(packet);
//Send the packet to the socket layer.
action.Invoke(packet.RawData, client.EndPoint);
new Thread(() =>
{
Stopwatch timeout = new Stopwatch();
Stopwatch timer = new Stopwatch();
timer.Start();
timeout.Start();
while (packetList.Contains(packet))
{
//Still no response from the remote connection -> send another packet
if (timer.ElapsedMilliseconds > 256)
{
action.Invoke(packet.RawData, client.EndPoint);
timer.Restart();
}
//No response after 2 seconds -> throw exception
if (timeout.ElapsedMilliseconds > 2048)
{
throw new Exception("Client has not responded to the request.");
}
}
}).Start();
}
private void ssl_OnPacketReceived(object sender, ServerPacketEventArgs e)
{
if (e.Packet.Command != Command.Ack)
return;
//Find matching packet in the packetList
NetworkPacket packet = packetList.Find(pkt => pkt.Checksum == e.Packet.Data[0]); //e.Packet.Data[0] is the checksum of the packet that was send out.
if (packet != null)
{
//Remove it to allow thread to exit
packetList.Remove(packet);
}
}

The easiest way to resolve the problem is to "guard" any calls to List with lock().
You can check here how to do it.
In short explanation is the following:
You should "guard" not thread safe operations following way
private object private_obj_to_be_used = new object();
lock(private_obj_to_be_used)
{
/// not thread safe operation goes here<br/>
}
Please note that you have to "guard" not only inserts or removes but the reads also.
Or you can check if there any "Concurrent" class is suitable for you.

Related

Problem with System.Thread.Timer execution

Performing data retrieval from socket.ReceiveFromAsync, there is some functionality to check for packages from sender to receiver. There is a certain class that stores statistics and all data for transmission. After sending the packet I start the timer to wait for a response, ideally I get a response and start killing the timer. But it happens that the response packet does not come back until the time specified in the timer, I send a repeat. This is where the weirdness doesn't always happen, but often it is. I haven't received the packet, the timer function starts to run, and I send the packet to repeat the timer on hold, at which point the packet comes in, such as a delayed packet, and I destroy the timer. but after the time of delay the function starts to run on sending a repeat as if I hadn't destroyed the timer.
I started to output the log from the ID of the thread in which the packets are received and the timer is executed, and in which thread the timer is destroyed, the destruction and retry of the false alarm is executed in different threads. How do I solve this problem ?
Receive code :
public void ReceiveAsync()
{
SocketAsyncEventArgs recieveArgs = new SocketAsyncEventArgs();
recieveArgs.SetBuffer(new byte[_data_size], 0, _data_size);
recieveArgs.RemoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
recieveArgs.Completed += ProcessRecievedPacket;
if (!_socket.ReceiveFromAsync(recieveArgs))
ProcessRecievedPacket(this, recieveArgs);
}
public void ProcessRecievedPacket(object sender, SocketAsyncEventArgs e)
{
try
{
Monitor.Enter(_lock_receive);
if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
{
ReceiveAsync();
...
}
Sending:
record is a class containing sending statistics.
record._start_wait_crl(onEventLog);
SendData(remoteAddr, data);
internal static void _start_wait_crl(this StatusNodeRecord record, _OnEventLog onEventLog)
{
try
{
record._timer_wait_crl_acp = new Timer((e) =>
{
StatusNodeRecord _record = (StatusNodeRecord)e;
record._lockSlimDispose.EnterWriteLock();
try
{
_record._socket.SendData(_record.Key.Item1, data);
_record?._timer_wait_crl_acp?.Change(_record._time_wait, Timeout.Infinite);
}
finally
{
record._lockSlimDispose.ExitWriteLock();
}
}, record, record._time_wait, Timeout.Infinite);
}
catch (Exception ex)
{
onEventLog?.Invoke(record, MethodInfo.GetCurrentMethod().Name, $"EXCEPTION::{ex.Message}. <-----------------------------------------------");
}
}
The moment I receive confirmation on the sender's side:
internal static void _dispose_wait_crl(this StatusNodeRecord record, _OnEventLog onEventLog)
{
record._lockSlimDispose.EnterWriteLock();
try
{
record?._timer_wait_crl_acp?.Change(Timeout.Infinite, Timeout.Infinite);
record? _timer_wait_crl_acp?Dispose();
record._timer_wait_crl_acp = null;
}
finally
{
record._lockSlimDispose.ExitWriteLock();
}
}
Help for a week I've been getting one and the same error The object doesn't exist, on a false positive the timer is already destroyed, and on a false positive it turns out that the methods should update the time and send a request, but it won't update the destroyed one.

C# sockets How can I handle unplanned disconnections on socket servers?

I am building a socket server in C#, and i have an issue with unplanned sockets disconnects.
For now, i am handling this like that:
private List<TCPClient> _acceptedClientsList = new List<TCPClient>();
public void checkIfStillConnected()
{
while (true)
{
lock (_sync)
{
for (int i = 0; i < _acceptedClientsList.Count(); ++i)
{
if (_acceptedClientsList[i].Client.Client.Poll(10, SelectMode.SelectRead) == true && (_acceptedClientsList[i]).Client.Client.Available == 0) // 5000 is the time to wait for a response, in microseconds.
{
NHDatabaseHandler dbHandler = new NHDatabaseHandler();
dbHandler.Init();
if (_acceptedClientsList[i].isVoipClient == true)
{
dbHandler.UpdateUserStatus(_acceptedClientsList[i].UserName, EStatus.Offline);
}
RemoveClient(i); // this function removes the selected client at i from the acceptedClientsList
i--;
}
}
}
}
}
But this is not optimized at all. This is a thread who checks every sockets status with the socket.poll, every time, infinitely...
I don't know if it's the best thing to do... It looks like it's heavy and weird.
Does anyone has an idea?
Thanks
It is best to have one dedicated thread to read incoming data from each socket. When unplanned socket disconnection occurs (for e.g. the client side network drops out or crashes), the socket will throw an exception. You can then catch exception, then close the socket connection and end the thread cleanly while keeping other socket running.
I learnt the TCP/IP communication from this tutorial.
http://www.codeproject.com/Articles/155282/TCP-Server-Client-Communication-Implementation
The author explains his implementation very well. It's worth learning from. You can reference it to rewrite your own library.

c# detecting disconnect from server with timer

I have a client type application that is receiving packets from remote server.
Now and then it so happens that for some reason server disconnects me.
Sometimes there are some problems on my end ISP drops internet etc.
I have been trying to catch those exceptions and goog-ling for an answer but at the end every one
points to "make a timer and check periodically for received packets."
Now i have a function that is receiving all incoming traffic.
This function is executed every time packet is received.
Now my idea is to create a function that will create timer with let say 50 seconds time out.
This function will reset timer to 0 each time packet is received and restart it.
If timer reach 50 seconds it will throw an error "disconnected!" and some logic will follow
how to reconnect.
Now main problem i have is ... i can not "pause" my main packet receiving function.
I have tried to make it in another thread but program keep recreating new threads , killing threads by ID is a bad practice and i haven't gone down that road ... yet.
Is this a how i should handle my problem or someone has a better idea?
Below is my packet receive function.
public void OnReceive()
{
try
{
recv_pack = locSec.TrIncom();
if (recv_pack != null)
{
foreach (Packet packet in recv_pack)
{
byte[] packet_bytes = packet.GetBytes();
PacketHandler.HandlePacket(packet, locSec);
//here i would check for packet receive with timer
//CheckDisconnect();
}
}
}
catch()
{}
}
So far i have come up with this:
public bool CheckDisconnect()
{
bool KeepGoing = true;
for(int i = 0 ; i <= 50 && KeepGoing; i++ )
{
Thead.Sleep(1000);
if(i == 50)
{
KeepGoing = false;
Console.WriteLine("Disconnected!");
// ... starting reconnect procedure
}
}
}
Not sure if i understand completely, but if those two functions are in the same thread, can't you just make a global variable that controls the OnReceive() function and set it to false in your CheckDisconnect() function?

C# handling two USB input data streams

I'm trying write a console application that could display and log two data streams incoming from two USB devices using WinUSB drivers.
Each data stream is made of 30 character long text messages that are sent at random intervals between 1ms and 200ms.
What would be the best general approach to the problem?
I have tried following:
Polling each device in turns in single main thread - there were many lost messages.
Using a global queue, polling each device in separate thread, stuffing messages into the queue. Then dequeueing and processing in main thread. Queueing and Dequeueing with apropriate lock. After a few seconds of proper work all messages from one device stop showing up.
Here's the Listener thread i use for every device:
static void Listener()
{
int currentDevice = 0;
byte[] incomingDataBuffer = new byte[30];
bool IsDataReceived = false;
while (true)
{
IsDataReceived = exxDevice.ReadBulk(currentDevice, ref incomingDataBuffer);
if (IsDataReceived == true)
{
AddToQueue(incomingDataBuffer);
}
Thread.Sleep(0);
}
}
And here is the main thread loop:
while (true)
{
do
{
usbEntry = GetFromQueue();
if (string.IsNullOrEmpty(usbEntry) == false)
{
Console.Write(usbEntry);
LogEntry(usbEntry);
}
} while (string.IsNullOrEmpty(usbEntry) == false);
Thread.Sleep(0);
}

C# thread started in another class

I have one main form class and another class. In the second class, I have a thread loop:
public void StartListening()
{
listening = true;
listener = new Thread(new ThreadStart(DoListening));
listener.Start();
}
// Listening for udp datagrams thread loop
/*=====================================================*/
private void DoListening()
{
while (listening)
{
IPEndPoint remoteIPEndPoint = new IPEndPoint(IPAddress.Any, port);
byte[] content = udpClient.Receive(ref remoteIPEndPoint);
if (content.Length > 0)
{
string message = Encoding.ASCII.GetString(content);
delegMessage(message);
}
}
}
// Stop listening for udp datagrams
/*=====================================================*/
public void StopListening()
{
lock (locker)
{
listening = false;
}
}
In main form class, I start this listening in class constructor
udp.StartListening();
And than, in this main form class, I have key hook event, too. In this event, I wan to stop thread running in the second class.
private void hook_KeyPressed(int key)
{
if (key == (int)Keys.LMenu)
altPressed = true;
if (key == (int)Keys.F4 && altPressed == true)
udp.StopListening();
}
Unfortunetely, the thread is still running.
Do you have some ideas about this??
Thank you very much.
Your thread is blocking at the byte[] content = udpClient.Receive(ref remoteIPEndPoint); line. The Receive method blocks until something is received.
You should use the asynchronous version (BeginReceive) instead.
Also, another flaw in your code - you check for the stopping condition without any synchronization. Here:
private void DoListening()
{
while (listening){ //this condition could stuck forever in 'false'
}
Actually, without a memory barrier, there is no guarantee, that a thread, that is running DoListening will ever see the change to listening var from other thread. You should at least use locking here (which provides memory barrier)
As #igelineau pointed out - your code is blocking on the receive call. If you don;t want to go down the async route (which I'd recommend) just send something to the udp port in your stop listening method.

Categories

Resources