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.
Related
I'm trying to implement file server that sends requested file to the client.
I implemented sending, and receiving part of Server and client, using TCP protocol.
My server sends data packet dequeued from the Packet queue until packet queue is empty, and my Client Receives until received packet number is same as desired packet number.
I used SendAsync() and ReceiveAsync() method from .Net framework.
My program Seems to have no problem when I debug it, But in the real run,
Client Seems to miss some packets sent from the server.. Even Server sent data packets, for some reason, client couldn't receive some data packets. I have no clue how this can happen.
Shouldn't TCP protocol ensure Receiving every packets sent from the server?
Do you have any clues why this happens?
Here is my code..
Receive_completed is callback method for ReceiveAsync() which is called after
ReceuveAsync is completed
and Process_receive function always reads every received bytes from ReceiveAsync(), and returns true if it has completed reading packet (Otherwise, return false, and Receive() method will be called again)
and.. ignore OperationCompleted, and _receivedProperly..
internal void Receive()//method for receiving the call
{
if (_operationState)
{
try
{
bool pending =_user.ClientSocket.ReceiveAsync(_receiveArg); // This will spawn a new thread and call Receive_completed as callback method
if (pending == false)
{
_receivePendingThread = new Thread(CallReceiveCompleted); //Start New thread
_receivePendingThread.Start();
}
}
catch (Exception exception)
{
ExceptionHandler(exception, CommunicatorError.ObjectDisposed);
}
}
}
private void Receive_completed(object sender, SocketAsyncEventArgs e)
{
if (e.LastOperation == SocketAsyncOperation.Receive)
{
bool transferCompleted = false;
try
{
if (e.BytesTransferred == 0)
{
throw new Exception("Socket Closed");
}
if (e.SocketError != SocketError.Success)
{
throw new Exception("Socket Error Occured");
}
}
catch (Exception exception)
{
ExceptionHandler(exception, CommunicatorError.SocketError);
return;
} //Checks for received bytes
//call process_receive here
transferCompleted = Process_receive(); //returns if more packets are left or not (This method Gurantees reading all received bytes from ReceiveAsync()
if (_receivedProperly&& _operationState) //Succeded process
{
if (transferCompleted && _operationState) Receive();//Receive if more bytes are left
else if (_operationState)
{// No more packets to be accepted additionally
CallReceiveCompleted();// Start Callback method
}
}
}
}
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?
I have a hardware component that I use with TCP communication. The class that control it has 3 jobs: Trigger the device, listen to incoming messages and raise an event when a message is received:
public class Hardware
{
public event Action<string> OnHardwareMessage;
private NetworkStream stream = new NetworkStream();
public Hardware()
{
Task.Factory.StartNew(() => { Listen(); });
}
private void Listen()
{
//listen to TCP port and raise an event when a message is received
byte[] bytes = new byte[1024];
int bytesRead = stream.Read(bytes, 0, bytes.Length);
string response = Encoding.ASCII.GetString(bytes, 0, bytesRead);
if (OnHardwareMessage != null)
OnHardwareMessage(response);
}
public void Trigger()
{
//Trigger the hardware component
//the response usually takes up to 5 seconds to arrive
}
}
This class is used in a loop inside a view-model:
public class MainViewModel
{
private static EventWaitHandle hardwareWaiter =
new EventWaitHandle(false, EventResetMode.AutoReset);
private Hardware hardware = new Hardware();
//what i'm doing now is holding a field for incoming event results
private string hardwareResult;
public MainViewModel()
{
hardware.OnHardwareMessage += hardware_OnHardwareMessage;
while (true)
{
hardware.Trigger();
if (hardwareWaiter.WaitOne(10000))
{
//is it possible to read the event argument here?
//do something with the event argument
someObservableCollection.Add(hardwareResult);
//clear the value
hardwareResult = string.Empty;
}
else
{
throw new Exception("Hardware did not respond on time");
}
}
}
//event listener for hardware events
private void hardware_OnHardwareMessage(string message)
{
hardwareResult = message;
hardwareWaiter.Set();
}
}
What I do is trigger the device and wait for up to 10 seconds for a response. What I'm doing now is holding a class scoped field, assign the message received inside the event listener, read it in the inside the loop and clear it.
My question is if there's any built in mechanism that could let me read the event argument directly after the EventWaitHandle was signaled (outside the event listener).
I would not base this on events. Maybe your listener should expose a BlockingCollection that represents the incoming stream of messages. Readers can then take from that collection with a timeout. If the timeout hits no message is taken and lost (this is a race condition that you have right now).
If you insist on using events use a closure to thread the message state:
string hardwareResult = null;
Action handler = (...) =>
{
hardwareResult = message;
hardwareWaiter.Set();
};
hardware.OnHardwareMessage += handler;
That way you only need a local variable which is scoped more tightly than a field.
There's the usual TCP bug as well: You assume to read an entire message. You could read one byte at a time instead.
I'm using the asynchronous methos BeginSend and I need some sort of a timeout mechanism. What I've implemented works fine for connect and receive timeouts but I have a problem with the BeginSend callback. Even a timeout of 25 seconds is often not enough and gets exceeded. This seems very strange to me and points towards a different cause.
public void Send(String data)
{
if (client.Connected)
{
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
client.NoDelay = true;
// Begin sending the data to the remote device.
IAsyncResult res = client.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), client);
if (!res.IsCompleted)
{
sendTimer = new System.Threading.Timer(SendTimeoutCallback, null, 10000, Timeout.Infinite);
}
}
else MessageBox.Show("No connection to target! Send");
}
private void SendCallback(IAsyncResult ar)
{
if (Interlocked.CompareExchange(ref sendTimeoutflag, 1, 0) != 0)
{
// the flag was set elsewhere, so return immediately.
return;
}
sendTimeoutflag = 0; //needs to be reset back to 0 for next reception
// we set the flag to 1, indicating it was completed.
if (sendTimer != null)
{
// stop the timer from firing.
sendTimer.Dispose();
}
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = client.EndSend(ar);
ef.updateUI("Sent " + bytesSent.ToString() + " bytes to server." + "\n");
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
private void SendTimeoutCallback(object obj)
{
if (Interlocked.CompareExchange(ref sendTimeoutflag, 2, 0) != 0)
{
// the flag was set elsewhere, so return immediately.
return;
}
// we set the flag to 2, indicating a timeout was hit.
sendTimer.Dispose();
client.Close(); // closing the Socket cancels the async operation.
MessageBox.Show("Connection to the target has been lost! SendTimeoutCallback");
}
I've tested timeout values up to 30 seconds. The value of 30 seconds has proved to be the only one never to time out. But that just seems like an overkill and I believe there's a different underlying cause.Any ideas as to why this could be happening?
Unfortunately, there's not enough code to completely diagnose this. You don't even show the declaration of sendTimeoutflag. The example isn't self-contained, so there's no way to test it. And you're not clear about exactly what happens (e.g. do you just get the timeout, do you complete a send and still get a timeout, does something else happen?).
That said, I see at least one serious bug in the code, which is your use of the sendTimeoutflag. The SendCallback() method sets this flag to 1, but it immediately sets it back to 0 again (this time without the protection of Interlocked.CompareExchange()). Only after it's set the value to 0 does it dispose the timer.
This means that even when you successfully complete the callback, the timeout timer is nearly guaranteed to have no idea and to close the client object anyway.
You can fix this specific issue by moving the assignment sendTimeoutflag = 0; to a point after you've actually completed the send operation, e.g. at the end of the callback method. And even then only if you take steps to ensure that the timer callback cannot execute past that point (e.g. wait for the timer's dispose to complete).
Note that even having fixed that specific issue, you may still have other bugs. Frankly, it's not clear why you want a timeout in the first place. Nor is it clear why you want to use lock-free code to implement your timeout logic. More conventional locking (i.e. Monitor-based with the lock statement) would be easier to implement correctly and would likely not impose a noticeable performance penalty.
And I agree with the suggestion that you would be better-served by using the async/await pattern instead of explicitly dealing with callback methods (but of course that would mean using a higher-level I/O object, since Socket doesn't suppose async/await).
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.