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?
Related
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).
I'm currently getting started on a socket programming project for a University network planning course. I'm also doing a Programming class in which we are learning C# so I thought it appropriate to use C# to complete this assignment.
The assignment is to create a simple Server-Client connection and have data sent between them. That is not too much of a problem, I've read a few tutorials and watched a few videos and I think I know what I'm doing. That part which has me a little confused is this:
"2) Every second, the server sends Client a command to seek measurement data, e.g., through a single letter "R" or "r" (request). (timing control is required here)."
This has me confused, What exactly is timing control? And how can I go about implementing it.
Thanks in advance.
EDIT: I found an "example" of timing control, but it is in the C/C++, Do I need to do something liek this?
/* Step 5.2: Send and Receive Data in loops */
time_old = getTime();
iterationStep = 1;
for (;;)
{
recvStatus = recv(TCPClient, recvBuffer,128,0);
if(recvStatus == 0)
break;
else if(recvStatus == SOCKET_ERROR)
{
printf("Failed in recv(): %d\n",WSAGetLastError());
break;
}
recvBuffer[recvStatus] = 0x00; /* '\0' */
time_new = getTime();
time_interval = time_new - time_old;
time_old = time_new;
printf("Step = %5d; Time Interval = %8.6f; Received String: %s\n", iterationStep,time_interval,recvBuffer);
iterationStep++;
}
/* if "EXIT" received, terminate the program */
if (!strcmp(recvBuffer,"EXIT"))
{
printf("TCP Server ready to terminate.");
break;
}
}
EDIT 2:
Im trying now to use this method but am having some trouble. I have created this method:
private static void SendRequest(Object source, ElapsedEventArgs e) {
byte[] buffer = Encoding.Default.GetBytes("WAAAAT");
acc.Send(buffer, 0, buffer.Length, 0);
}
But as you can see, I cannot use the "acc" socket because I can set it as a parameter. I tried to but then I get a lot of errors when calling the method, any advice?
It sounds like you will need to use the "System.Timers.Timer" class to execute your "send request" function every second.
Example:
static void Main()
{
// Create a timer with a one second interval.
aTimer = new System.Timers.Timer(1000);
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += SendRequest;
aTimer.Enabled = true;
}
private static void SendRequest(Object source, ElapsedEventArgs e)
{
// maybe end existing request if not completed?
// send next request
}
Whether you time out(cancel) any existing requests before starting a new one will depend on your requirements as it is also possible to have many requests running in parallel. If you do need to kill a request, you can do so by disposing the System.Net.Sockets.Socket that initiated the connection attempt (you will need to handle any errors thrown by the Socket.Connect).
Timing control sounds like a mechanism to insure that the requests are fired 1 sec apart and that if a request doesn't complete in a timely fashion to terminate that request and fire the next one.
Take a scenario
Request 1 fires at point 0
After 1 sec request 1 hasn't received an answer but request 2 needs to fire.
You probably need to implement a timeout system based on a clock.
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.
I'm receiving periodically some data via Serial Port, in order to plot it and do some more stuff. In order to achive this purpose, I send the data from my microcontroller to my computer with a header, which specifies the length of each packet.
I have the program running and working perfectly except a one last detail. When the header specifies a lenght, my program will not stop until it reachs that amount of bytes. So if, for some reason, some data from one packet is missed, the program wait and take the beginning of the next packet...and then start the real problems. Since that moment, every fails.
I thought about rising a Timer every 0.9 seconds ( the packages come every second) who will give a command in order to comeback to wait and reset variables. But I don't know how to do it, I tried but I obtain errors while running. Since IndCom ( see next code) resets in the midle of some function and errors as "Index out of bounds" arises.
I attach my code ( without timer)
private void routineRx(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
try
{
int BytesWaiting;
do
{
BytesWaiting = this.serialPort.BytesToRead;
//Copy it to the BuffCom
while (BytesWaiting > 0)
{
BuffCom[IndCom] = (byte)this.serialPort.ReadByte();
IndCom = IndCom + 1;
BytesWaiting = BytesWaiting - 1;
}
} while (IndCom < HeaderLength);
//I have to read until I got the whole Header which gives the info about the current packet
PacketLength = getIntInfo(BuffCom,4);
while (IndCom < PacketLength)
{
BytesWaiting = this.serialPort.BytesToRead;
//Copy it to the BuffCom
while (BytesWaiting > 0)
{
BuffCom[IndCom] = (byte)this.serialPort.ReadByte();
IndCom = IndCom + 1;
BytesWaiting = BytesWaiting - 1;
}
}
//If we have a packet--> check if it is valid and, if so, what kind of packet is
this.Invoke(new EventHandler(checkPacket));
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
I'm new in object-oriented programming and c#, so be clement, please! And thank you very much
What you might do is use a Stopwatch.
const long COM_TIMEOUT = 500;
Stopwatch spw = new Stopwatch();
spw.Restart();
while (IndCom < PacketLength)
{
//read byte, do stuff
if (spw.ElapsedMilliseconds > COM_TIMEOUT) break; //etc
}
Restart the stopwatch at the beginning and check the time in each while loop, then break out(and clean up) if the timeout hits. 900ms is probably too much, even, if you're only expecting a few bytes. Com traffic is quite fast - if you don't get the whole thing immediately it's probably not coming.
I like to use termination characters in communication protocols (like [CR], etc). This allows you to read until you find the termination character, then stop. This prevents reading into the next command. Even if you don't want to use termination characters, changing your code to something like this :
while (IndCom < PacketLength)
{
if (serialPort.BytesToRead > 0)
{
BuffCom[IndCom] = (byte)this.serialPort.ReadByte();
IndCom++;
}
}
it allows you to stop when you reach your packet size, leaving any remaining characters in the buffer for the next round through (ie: the next command). You can add the stopwatch timeout in the above also.
The other nice thing about termination characters is that you don't have to know in advance how long the packet should be - you just read until you reach the termination character and then process/parse the whole thing once you've got it. It makes your two-step port read into a one-step port read.
On my multithreaded server I am experiencincg troubles with connections that are not coming from the proper Client and so hang unathorized. I did not want to create new thread only for checking if clients are connected for some time without authorization. Instead of this, I have add this checking to RecieveData thread, shown on the code below. Do you see some performance issue or this is acceptable? The main point is that everytime client is connected (and Class client is instantionized) it starts stopwatch. And so I add to this thread condition - if the time is greater than 1 and the client is still not authorized, its added on the list of clients determinated for disconnection. Thanks
EDIT: This While(true) is RecieveData thread. I am using async. operations - from tcplistener.BeginAccept to threadpooling. I have updated the code to let you see more.
protected void ReceiveData()
{
List<Client> ClientsToDisconnect = new List<Client>();
List<System.Net.Sockets.Socket> sockets = new List<System.Net.Sockets.Socket>();
bool noClients = false;
while (true)
{
sockets.Clear();
this.mClientsSynchronization.TryEnterReadLock(-1);
try
{
for (int i = 0; i < this.mClientsValues.Count; i++)
{
Client c = this.mClientsValues[i];
if (!c.IsDisconnected && !c.ReadingInProgress)
{
sockets.Add(c.Socket);
}
//clients connected more than 1 second without recieved name are suspect and should be disconnected
if (c.State == ClientState.NameNotReceived && c.watch.Elapsed.TotalSeconds > 1)
ClientsToDisconnect.Add(c);
}
if (sockets.Count == 0)
{
continue;
}
}
finally
{
this.mClientsSynchronization.ExitReadLock();
}
try
{
System.Net.Sockets.Socket.Select(sockets, null, null, RECEIVE_DATA_TIMEOUT);
foreach (System.Net.Sockets.Socket s in sockets)
{
Client c = this.mClients[s];
if (!c.SetReadingInProgress())
{
System.Threading.ThreadPool.QueueUserWorkItem(c.ReadData);
}
}
//remove clients in ClientsToDisconnect
foreach (Client c in ClientsToDisconnect)
{
this.RemoveClient(c,true);
}
}
catch (Exception e)
{
//this.OnExceptionCaught(this, new ExceptionCaughtEventArgs(e, "Exception when reading data."));
}
}
}
I think I see what you are trying to do and I think a better way would be to store new connections in a holding area until they have properly connected.
I'm not positive but it looks like your code could drop a valid connection. If a new connection is made after the checking section and the second section takes more than a second all the timers would time out before you could verify the connections. This would put the new connections in both the socket pool AND the ClientsToDisconnect pool. Not good. You would drop a currently active connection and chaos would ensue.
To avoid this, I would make the verification of a connection a seperate thread from the using of the connection. That way you won't get bogged down in timing issues (well...you still will but that is what happens when we work with threads and sockets) and you are sure that all the sockets you are using won't get closed by you.
My gut reaction is that while (true) plus if (sockets.Count == 0) continue will lead to heartache for your CPU. Why don't you put this on a Timer or something so that this function is only called every ~.5s? Is the 1s barrier really that important?