tags:

views:

363

answers:

2

I'm writing a configuration tool for a device that can communicate via telnet. The tool sends a command via TcpClient.GetStream().Write(...), and then checks for the device response via TcpClient.GetStream().ReadByte(). This works fine in unit tests or when I'm stepping through code slowly. If I run the config tool such that it performs multiple commands consecutively, then the behavior of the read is inconsistent. By inconsistent I mean sometimes the data is missing, incomplete or partially garbled. So even though the device performed the operation and responded, my code to check for the response was unreliable. I "fixed" this problem by adding a Thread.Sleep to make sure the read method waits long enough for the device to complete its job and send back the whole response (in this case 1.5 seconds was a safe amount). I feel like this is wrong, blocking everything for a fixed time, and I wonder if there is a better way to get the read method to wait only long enough to get the whole response from the device.

private string Read()
{
    if (!tcpClient.Connected)
  throw (new Exception("Read() failed: Telnet connection not available."));
 StringBuilder sb = new StringBuilder();
 do
 {
  ParseTelnet(ref sb);
  System.Threading.Thread.Sleep(1500);
 } while (tcpClient.Available > 0);
 return sb.ToString();
}
private void ParseTelnet(ref StringBuilder sb)
{
 while (tcpClient.Available > 0)
 {
  int input = tcpClient.GetStream().ReadByte();
  switch (input)
  {
   // parse the input
   // ... do other things in special cases
   default:
    sb.Append((char)input);
    break;
  }
 }
}
+2  A: 

It seems to me that the main problem is that you don't have any idea of when the response is "finished" - so you're just waiting until there's no more data available right now.

A well-designed protocol which has multiple requests and responses should make it clear when each request (and response) finishes. Sometimes that will be using delimiters (e.g. the response continues until you get an empty line on its own) and sometimes it will be using a length-prefix ("the next 100 bytes are the response"). Length-prefixing is often easier to handle because you don't need to work out how to escape the data if you want the delimiter itself in "normal" data. On the other hand, that means you need to have all the data before you can start writing the response. There are alternative such as chunking - write length-prefixed chunks, with (say) a length of 0 to mean you're finished.

As an aside: - You're currently effectively using ISO-8859-1 as the encoding; is this deliberate? - The StringBuilder parameter doesn't need to be passed by reference.

Jon Skeet
Exactly. Is there a way to know when the device has finished sending me data? I have not control over what the device sends me, it is a 3rd party device. I have a pretty good idea of what the device "should" send me, which is what I'm using to make sure the operation was completed.
Dan Bailiff
A: 

do you solve this problem? i have the same problem just as you described. it is nice of you to share the solution with me.thanks email:[email protected]

sophy
This is not an answer - please delete it and post it as a comment to the question.
Ani