I am working on a project where I should run commands on Unix servers and get the full output of those commands. For this purpose, I am using Minimaslistic Telnet Library from code project (http://www.codeproject.com/Articles/19071/Quick-tool-A-minimalistic-Telnet-library). For now, everything works fine excepting the output, because I want to read it all, not just a portion of it. I can have commands that may take long time. Here is the read output method in the Minimaslistic Telnet Library :
public string Read()
{
if (!tcpSocket.Connected) return null;
StringBuilder sb=new StringBuilder();
do
{
ParseTelnet(sb);
System.Threading.Thread.Sleep(TimeOutMs);
} while (tcpSocket.Available > 0);
return sb.ToString();
}
void ParseTelnet(StringBuilder sb)
{
while (tcpSocket.Available > 0)
{
int input = tcpSocket.GetStream().ReadByte();
switch (input)
{
case -1 :
break;
case (int)Verbs.IAC:
// interpret as command
int inputverb = tcpSocket.GetStream().ReadByte();
if (inputverb == -1) break;
switch (inputverb)
{
case (int)Verbs.IAC:
//literal IAC = 255 escaped, so append char 255 to string
sb.Append(inputverb);
break;
case (int)Verbs.DO:
case (int)Verbs.DONT:
case (int)Verbs.WILL:
case (int)Verbs.WONT:
// reply to all commands with "WONT", unless it is SGA (suppres go ahead)
int inputoption = tcpSocket.GetStream().ReadByte();
if (inputoption == -1) break;
tcpSocket.GetStream().WriteByte((byte)Verbs.IAC);
if (inputoption == (int)Options.SGA )
tcpSocket.GetStream().WriteByte(inputverb == (int)Verbs.DO ? (byte)Verbs.WILL:(byte)Verbs.DO);
else
tcpSocket.GetStream().WriteByte(inputverb == (int)Verbs.DO ? (byte)Verbs.WONT : (byte)Verbs.DONT);
tcpSocket.GetStream().WriteByte((byte)inputoption);
break;
default:
break;
}
break;
default:
sb.Append( (char)input );
break;
}
}
}
This code sample reads output, but asynchronously, I need it to wait for output before quitting. Is there any idea about changing the code to meet my requirements? Thank you!
I agree with Joachim, calling the read in a loop and parsing for the end out the output is the best approach. Unfortunately for me, my output didn't have a standardize ending for each command I executed. Instead, I used the read timeout of the stream to approximate the end of the output (I realize this isn't perfect). I set a higher initial timeout to allow the data to start flowing, and then lowered the timeout to find the end of the output. It looks something like this:
static string ReadFromStream(int initialTimeout, int subsequentTimeout)
{
// Initialize output
string output = null;
try
{
// Set initial read timeout -- This is needed because occasionally
// it takes a while before data starts flowing
stream.ReadTimeout = initialTimeout;
while (stream.CanRead)
{
// Read bytes in from stream
readBuffer = new byte[tcpClient.ReceiveBufferSize];
stream.Read(readBuffer, 0, tcpClient.ReceiveBufferSize);
// Convert the bytes to string and save to output
output = string.Format("{0}{1}", output, Encoding.ASCII.GetString(readBuffer).Trim());
// Set subsequent read timeout
stream.ReadTimeout = subsequentTimeout;
}
}
// Since we don't know when the output will end, we wait for, and catch the timeout
catch (IOException) { }
// Return output
return output;
}