StreamReader not reading all lines

G

Guest

Hello,

First let me tell you that I'm very new to C# and learning as I go. I'm
trying to write a client application to communicate with a server (that I
didn't write). Each message from the server is on one line (\r\n at end) and
is formed as [Message] [Optional Argument1] [Optional Argument2] - each of
which is seperated by a space. Arguments with spaces in them are enclosed in
quotations.

So, I'm able to open a connection to the server. When I send a message to
it, it immediately responds and I parse that using a streaReader.Readline().
- That part works. The problem is that the server is also sending status
messages every couple of seconds which seem to get lost. I didn't know how
to have it raise an event when data is present at the stream, so I setup a
timer to poll the stream.

I've tried using "streamReader.Peek() != null" but it hangs, I've tried just
streamReader.ReadLine() but it hangs. Any suggestions are greatly
appreciated. I'm using Beta 2

Code is below

Thanks in advance!!
Joe


using System;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Threading;
using System.Net.Sockets;
using System.IO;

public delegate void ConnectionHandler(bool State);
public delegate void ControlChangeHandler(String Message);

public partial class MMConnection : Form
{

//--------------------------------------------------------------
// Class Variables
private NetworkStream netStream;
private StreamWriter netWriter;
private StreamReader netReader;
public TcpClient netClient;
private bool netClientStart = false;
private bool netClientConnected = false;

private System.Net.IPAddress ipAddress =
System.Net.IPAddress.Parse("127.0.0.1");
private int ipPort = 1632;
private String strUsername = "Contemporary";
private String strPassword = "techspa";
private bool blnLoggedIn = false;

// Define events this class can raise
public event ConnectionHandler OnConnectionChanged;
public event ControlChangeHandler OnControlChanged;

//--------------------------------------------------------------
// Constructor
public MMConnection()
{
InitializeComponent();
}

// Startup the client
public void ConnectionStart()
{
netClientStart = true;
tmrStatus.Enabled = true;
}

public void ConnectionStop ()
{
try
{
logToScreen("Closing connection");

// Close connection
netWriter.Close();
netReader.Close();
netStream.Close();
netClient.Close();
}
catch (Exception e)
{
logToScreen("Error closing connection: " + e.Message.ToString());
}
}

private void StreamWrite (string strMessage)
{
try
{
if (strMessage != "sg") logToScreen("Sending string: " + strMessage);
netWriter.Write(strMessage + "\r\n");
netWriter.Flush();
}
catch (Exception e)
{
netClientConnected = false; // Cannot send - client must have disconnected
Console.WriteLine("Error sending string: " + e.Message.ToString());
}
}

public void MessageSend(string strMessage)
{
StreamWrite(strMessage);
}

// Send Password to the server
private void sendLogin()
{
StreamWrite("li" + " " + strUsername + " " + strPassword);
}

// Parse responses from the server
private void ProcessString(String strData)
{
int foundPosition; //Position of the first space
String firstToken; //The first token (command or error

// Parse out the first token
foundPosition = strData.IndexOf(@" ");
if (foundPosition > -1)
{
firstToken = strData.Substring(0, foundPosition).ToString();
}
else
{
firstToken = strData.ToString();
}

// Act on the first token
switch (firstToken)
{
case "notLoggedIn":
sendLogin();
break;

case "loggedIn":
blnLoggedIn = true;
logToScreen("Logged into MediaMatrix");
UpdateConnectionIndicator(netClient.Connected);
break;

case "statusIs":
blnLoggedIn = true;
break;

case "valueIs":
OnControlChanged(strData);
break;

default: //no token
break;
}
}

private void tmrStatus_Tick(object sender, EventArgs e)
{
if (netClientConnected)
{
tmrRead.Enabled = true;
StreamWrite("sg"); //Status Get
}
else
{
if (netClientStart)
{
try
{

netClient = new TcpClient();
// Create TcpClient and connect to server
netClient.Connect(ipAddress, ipPort);
//UpdateConnectionIndicator(netClient.Connected); //Moved to after
login

// Get network Stream associated with TcpClient
netStream = netClient.GetStream();
netClientConnected = true;
logToScreen("Connection Successfull to: " + ipAddress + " port: " +
ipPort);

// Create readers and writers
netReader = new StreamReader(netStream);
netWriter = new StreamWriter(netStream);
Console.WriteLine("Got Streams!");
}
catch (Exception error)
{
Console.Write ("Error: " + error.ToString());
netClientConnected = false;
}
}
}

// Update the color
//UpdateConnectionIndicator(netClient.Connected);
}

private void logToScreen(String strMessage)
{
lstReceive.Items.Add(strMessage);
Console.WriteLine(strMessage);
}

private void btnSend_Click(object sender, EventArgs e)
{
StreamWrite(txtSend.Text);
}

private void tmrRead_Tick(object sender, EventArgs e)
{
String strData;

try
{
// Read and display lines from the network stream
//while(netStream.DataAvailable)
// logToScreen("End of Stream: " + netReader.EndOfStream);
// logToScreen("Net Reader: " + netReader.ReadLine().ToString());
// logToScreen("End of Stream: " + netReader.EndOfStream);
while (netStream.DataAvailable)
{
try
{
// Grab data from socket
strData = netReader.ReadLine();

// Clean it up a bit
strData = strData.Trim(new char[3] { '\a', '\r', '\n' });

// Send it on to be parsed
logToScreen("Received string: " + strData);
ProcessString(strData);
}
catch (Exception ex)
{
logToScreen("Error reading string: " + ex.Message.ToString());
}
}
}
catch (Exception exc)
{
logToScreen("Error Receiving: " + exc.Message.ToString());
}
}

public static string[] Tokenize(string strIncoming)
{
//TODO: Put regular expresstion
System.Text.RegularExpressions.Regex regFilter = new
System.Text.RegularExpressions.Regex
( @"\a|\s" );

return (regFilter.Split(strIncoming));
}

private void UpdateConnectionIndicator(bool blnConnected)
{
if (blnConnected)
{
staStripConnected.Text = "Connected";
staStripConnected.BackColor = System.Drawing.Color.LightGreen;
}
else
{
staStripConnected.Text = "Not Connected";
staStripConnected.BackColor = System.Drawing.Color.Red;
}

//Raise Event to calling form
OnConnectionChanged(blnConnected);
}

}// MMConnection end
 
N

Nicholas Paldino [.NET/C# MVP]

JoKur,

What I would do is have the StreamReader run in a loop, reading lines as
they come (it will hang in between). The key though is to have the
StreamReader run on another thread, which would raise an event when the
message is received. This way, you won't have to worry about hanging your
application, and can get notifications when the messages come in.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

JoKur said:
Hello,

First let me tell you that I'm very new to C# and learning as I go. I'm
trying to write a client application to communicate with a server (that I
didn't write). Each message from the server is on one line (\r\n at end)
and
is formed as [Message] [Optional Argument1] [Optional Argument2] - each of
which is seperated by a space. Arguments with spaces in them are enclosed
in
quotations.

So, I'm able to open a connection to the server. When I send a message to
it, it immediately responds and I parse that using a
streaReader.Readline().
- That part works. The problem is that the server is also sending status
messages every couple of seconds which seem to get lost. I didn't know
how
to have it raise an event when data is present at the stream, so I setup a
timer to poll the stream.

I've tried using "streamReader.Peek() != null" but it hangs, I've tried
just
streamReader.ReadLine() but it hangs. Any suggestions are greatly
appreciated. I'm using Beta 2

Code is below

Thanks in advance!!
Joe


using System;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Threading;
using System.Net.Sockets;
using System.IO;

public delegate void ConnectionHandler(bool State);
public delegate void ControlChangeHandler(String Message);

public partial class MMConnection : Form
{

//--------------------------------------------------------------
// Class Variables
private NetworkStream netStream;
private StreamWriter netWriter;
private StreamReader netReader;
public TcpClient netClient;
private bool netClientStart = false;
private bool netClientConnected = false;

private System.Net.IPAddress ipAddress =
System.Net.IPAddress.Parse("127.0.0.1");
private int ipPort = 1632;
private String strUsername = "Contemporary";
private String strPassword = "techspa";
private bool blnLoggedIn = false;

// Define events this class can raise
public event ConnectionHandler OnConnectionChanged;
public event ControlChangeHandler OnControlChanged;

//--------------------------------------------------------------
// Constructor
public MMConnection()
{
InitializeComponent();
}

// Startup the client
public void ConnectionStart()
{
netClientStart = true;
tmrStatus.Enabled = true;
}

public void ConnectionStop ()
{
try
{
logToScreen("Closing connection");

// Close connection
netWriter.Close();
netReader.Close();
netStream.Close();
netClient.Close();
}
catch (Exception e)
{
logToScreen("Error closing connection: " + e.Message.ToString());
}
}

private void StreamWrite (string strMessage)
{
try
{
if (strMessage != "sg") logToScreen("Sending string: " + strMessage);
netWriter.Write(strMessage + "\r\n");
netWriter.Flush();
}
catch (Exception e)
{
netClientConnected = false; // Cannot send - client must have disconnected
Console.WriteLine("Error sending string: " + e.Message.ToString());
}
}

public void MessageSend(string strMessage)
{
StreamWrite(strMessage);
}

// Send Password to the server
private void sendLogin()
{
StreamWrite("li" + " " + strUsername + " " + strPassword);
}

// Parse responses from the server
private void ProcessString(String strData)
{
int foundPosition; //Position of the first space
String firstToken; //The first token (command or error

// Parse out the first token
foundPosition = strData.IndexOf(@" ");
if (foundPosition > -1)
{
firstToken = strData.Substring(0, foundPosition).ToString();
}
else
{
firstToken = strData.ToString();
}

// Act on the first token
switch (firstToken)
{
case "notLoggedIn":
sendLogin();
break;

case "loggedIn":
blnLoggedIn = true;
logToScreen("Logged into MediaMatrix");
UpdateConnectionIndicator(netClient.Connected);
break;

case "statusIs":
blnLoggedIn = true;
break;

case "valueIs":
OnControlChanged(strData);
break;

default: //no token
break;
}
}

private void tmrStatus_Tick(object sender, EventArgs e)
{
if (netClientConnected)
{
tmrRead.Enabled = true;
StreamWrite("sg"); //Status Get
}
else
{
if (netClientStart)
{
try
{

netClient = new TcpClient();
// Create TcpClient and connect to server
netClient.Connect(ipAddress, ipPort);
//UpdateConnectionIndicator(netClient.Connected); //Moved to after
login

// Get network Stream associated with TcpClient
netStream = netClient.GetStream();
netClientConnected = true;
logToScreen("Connection Successfull to: " + ipAddress + " port: " +
ipPort);

// Create readers and writers
netReader = new StreamReader(netStream);
netWriter = new StreamWriter(netStream);
Console.WriteLine("Got Streams!");
}
catch (Exception error)
{
Console.Write ("Error: " + error.ToString());
netClientConnected = false;
}
}
}

// Update the color
//UpdateConnectionIndicator(netClient.Connected);
}

private void logToScreen(String strMessage)
{
lstReceive.Items.Add(strMessage);
Console.WriteLine(strMessage);
}

private void btnSend_Click(object sender, EventArgs e)
{
StreamWrite(txtSend.Text);
}

private void tmrRead_Tick(object sender, EventArgs e)
{
String strData;

try
{
// Read and display lines from the network stream
//while(netStream.DataAvailable)
// logToScreen("End of Stream: " + netReader.EndOfStream);
// logToScreen("Net Reader: " + netReader.ReadLine().ToString());
// logToScreen("End of Stream: " + netReader.EndOfStream);
while (netStream.DataAvailable)
{
try
{
// Grab data from socket
strData = netReader.ReadLine();

// Clean it up a bit
strData = strData.Trim(new char[3] { '\a', '\r', '\n' });

// Send it on to be parsed
logToScreen("Received string: " + strData);
ProcessString(strData);
}
catch (Exception ex)
{
logToScreen("Error reading string: " + ex.Message.ToString());
}
}
}
catch (Exception exc)
{
logToScreen("Error Receiving: " + exc.Message.ToString());
}
}

public static string[] Tokenize(string strIncoming)
{
//TODO: Put regular expresstion
System.Text.RegularExpressions.Regex regFilter = new
System.Text.RegularExpressions.Regex
( @"\a|\s" );

return (regFilter.Split(strIncoming));
}

private void UpdateConnectionIndicator(bool blnConnected)
{
if (blnConnected)
{
staStripConnected.Text = "Connected";
staStripConnected.BackColor = System.Drawing.Color.LightGreen;
}
else
{
staStripConnected.Text = "Not Connected";
staStripConnected.BackColor = System.Drawing.Color.Red;
}

//Raise Event to calling form
OnConnectionChanged(blnConnected);
}

}// MMConnection end
 
J

Jon Skeet [C# MVP]

JoKur said:
First let me tell you that I'm very new to C# and learning as I go. I'm
trying to write a client application to communicate with a server (that I
didn't write). Each message from the server is on one line (\r\n at end) and
is formed as [Message] [Optional Argument1] [Optional Argument2] - each of
which is seperated by a space. Arguments with spaces in them are enclosed in
quotations.

So, I'm able to open a connection to the server. When I send a message to
it, it immediately responds and I parse that using a streaReader.Readline().
- That part works. The problem is that the server is also sending status
messages every couple of seconds which seem to get lost. I didn't know how
to have it raise an event when data is present at the stream, so I setup a
timer to poll the stream.

I've tried using "streamReader.Peek() != null" but it hangs, I've tried just
streamReader.ReadLine() but it hangs. Any suggestions are greatly
appreciated. I'm using Beta 2

Does the server flush the stream after sending the status code? It
sounds like it isn't, or that it's not sending a line terminator after
the status code.

Have you tried using a network sniffer to check that the information is
coming over the wire?
 
G

Guest

Jon,

It ends each line with \r\n, which is supposedly what ReadLine() looks for.
I can see this when I connect using Telnet.

I had another thought, is it possible that the server is sending more than
one line but when I'm reading them, I'm only grabbing the first line?

In other words... What happens if I'm accessing the stream (like writing to
it), when something else comes in? Is there a way to ask how many lines it
sees and then do a ReadLine() for each one?

--
Thanks
Joe


Jon Skeet said:
JoKur said:
First let me tell you that I'm very new to C# and learning as I go. I'm
trying to write a client application to communicate with a server (that I
didn't write). Each message from the server is on one line (\r\n at end) and
is formed as [Message] [Optional Argument1] [Optional Argument2] - each of
which is seperated by a space. Arguments with spaces in them are enclosed in
quotations.

So, I'm able to open a connection to the server. When I send a message to
it, it immediately responds and I parse that using a streaReader.Readline().
- That part works. The problem is that the server is also sending status
messages every couple of seconds which seem to get lost. I didn't know how
to have it raise an event when data is present at the stream, so I setup a
timer to poll the stream.

I've tried using "streamReader.Peek() != null" but it hangs, I've tried just
streamReader.ReadLine() but it hangs. Any suggestions are greatly
appreciated. I'm using Beta 2

Does the server flush the stream after sending the status code? It
sounds like it isn't, or that it's not sending a line terminator after
the status code.

Have you tried using a network sniffer to check that the information is
coming over the wire?
 
G

Guest

Nicholas,

Thanks for the suggestion. I had started by trying this approach but
couldn't figure out how to get the polling thread to raise a message to the
running program. Do you have any examples/samples of this?
--
Thanks
Joe


Nicholas Paldino said:
JoKur,

What I would do is have the StreamReader run in a loop, reading lines as
they come (it will hang in between). The key though is to have the
StreamReader run on another thread, which would raise an event when the
message is received. This way, you won't have to worry about hanging your
application, and can get notifications when the messages come in.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

JoKur said:
Hello,

First let me tell you that I'm very new to C# and learning as I go. I'm
trying to write a client application to communicate with a server (that I
didn't write). Each message from the server is on one line (\r\n at end)
and
is formed as [Message] [Optional Argument1] [Optional Argument2] - each of
which is seperated by a space. Arguments with spaces in them are enclosed
in
quotations.

So, I'm able to open a connection to the server. When I send a message to
it, it immediately responds and I parse that using a
streaReader.Readline().
- That part works. The problem is that the server is also sending status
messages every couple of seconds which seem to get lost. I didn't know
how
to have it raise an event when data is present at the stream, so I setup a
timer to poll the stream.

I've tried using "streamReader.Peek() != null" but it hangs, I've tried
just
streamReader.ReadLine() but it hangs. Any suggestions are greatly
appreciated. I'm using Beta 2

Code is below

Thanks in advance!!
Joe


using System;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Threading;
using System.Net.Sockets;
using System.IO;

public delegate void ConnectionHandler(bool State);
public delegate void ControlChangeHandler(String Message);

public partial class MMConnection : Form
{

//--------------------------------------------------------------
// Class Variables
private NetworkStream netStream;
private StreamWriter netWriter;
private StreamReader netReader;
public TcpClient netClient;
private bool netClientStart = false;
private bool netClientConnected = false;

private System.Net.IPAddress ipAddress =
System.Net.IPAddress.Parse("127.0.0.1");
private int ipPort = 1632;
private String strUsername = "Contemporary";
private String strPassword = "techspa";
private bool blnLoggedIn = false;

// Define events this class can raise
public event ConnectionHandler OnConnectionChanged;
public event ControlChangeHandler OnControlChanged;

//--------------------------------------------------------------
// Constructor
public MMConnection()
{
InitializeComponent();
}

// Startup the client
public void ConnectionStart()
{
netClientStart = true;
tmrStatus.Enabled = true;
}

public void ConnectionStop ()
{
try
{
logToScreen("Closing connection");

// Close connection
netWriter.Close();
netReader.Close();
netStream.Close();
netClient.Close();
}
catch (Exception e)
{
logToScreen("Error closing connection: " + e.Message.ToString());
}
}

private void StreamWrite (string strMessage)
{
try
{
if (strMessage != "sg") logToScreen("Sending string: " + strMessage);
netWriter.Write(strMessage + "\r\n");
netWriter.Flush();
}
catch (Exception e)
{
netClientConnected = false; // Cannot send - client must have disconnected
Console.WriteLine("Error sending string: " + e.Message.ToString());
}
}

public void MessageSend(string strMessage)
{
StreamWrite(strMessage);
}

// Send Password to the server
private void sendLogin()
{
StreamWrite("li" + " " + strUsername + " " + strPassword);
}

// Parse responses from the server
private void ProcessString(String strData)
{
int foundPosition; //Position of the first space
String firstToken; //The first token (command or error

// Parse out the first token
foundPosition = strData.IndexOf(@" ");
if (foundPosition > -1)
{
firstToken = strData.Substring(0, foundPosition).ToString();
}
else
{
firstToken = strData.ToString();
}

// Act on the first token
switch (firstToken)
{
case "notLoggedIn":
sendLogin();
break;

case "loggedIn":
blnLoggedIn = true;
logToScreen("Logged into MediaMatrix");
UpdateConnectionIndicator(netClient.Connected);
break;

case "statusIs":
blnLoggedIn = true;
break;

case "valueIs":
OnControlChanged(strData);
break;

default: //no token
break;
}
}

private void tmrStatus_Tick(object sender, EventArgs e)
{
if (netClientConnected)
{
tmrRead.Enabled = true;
StreamWrite("sg"); //Status Get
}
else
{
if (netClientStart)
{
try
{

netClient = new TcpClient();
// Create TcpClient and connect to server
netClient.Connect(ipAddress, ipPort);
//UpdateConnectionIndicator(netClient.Connected); //Moved to after
login

// Get network Stream associated with TcpClient
netStream = netClient.GetStream();
netClientConnected = true;
logToScreen("Connection Successfull to: " + ipAddress + " port: " +
ipPort);

// Create readers and writers
netReader = new StreamReader(netStream);
netWriter = new StreamWriter(netStream);
Console.WriteLine("Got Streams!");
}
catch (Exception error)
{
Console.Write ("Error: " + error.ToString());
netClientConnected = false;
}
}
}

// Update the color
//UpdateConnectionIndicator(netClient.Connected);
}

private void logToScreen(String strMessage)
{
lstReceive.Items.Add(strMessage);
Console.WriteLine(strMessage);
}

private void btnSend_Click(object sender, EventArgs e)
{
StreamWrite(txtSend.Text);
}

private void tmrRead_Tick(object sender, EventArgs e)
{
String strData;

try
{
// Read and display lines from the network stream
//while(netStream.DataAvailable)
// logToScreen("End of Stream: " + netReader.EndOfStream);
// logToScreen("Net Reader: " + netReader.ReadLine().ToString());
// logToScreen("End of Stream: " + netReader.EndOfStream);
while (netStream.DataAvailable)
{
try
{
// Grab data from socket
strData = netReader.ReadLine();

// Clean it up a bit
strData = strData.Trim(new char[3] { '\a', '\r', '\n' });

// Send it on to be parsed
logToScreen("Received string: " + strData);
ProcessString(strData);
}
catch (Exception ex)
{
logToScreen("Error reading string: " + ex.Message.ToString());
}
}
}
catch (Exception exc)
{
logToScreen("Error Receiving: " + exc.Message.ToString());
}
}

public static string[] Tokenize(string strIncoming)
{
//TODO: Put regular expresstion
System.Text.RegularExpressions.Regex regFilter = new
System.Text.RegularExpressions.Regex
( @"\a|\s" );

return (regFilter.Split(strIncoming));
}

private void UpdateConnectionIndicator(bool blnConnected)
{
if (blnConnected)
{
staStripConnected.Text = "Connected";
staStripConnected.BackColor = System.Drawing.Color.LightGreen;
}
else
{
staStripConnected.Text = "Not Connected";
staStripConnected.BackColor = System.Drawing.Color.Red;
}
 
N

Nicholas Paldino [.NET/C# MVP]

JoKur,

Why not just create an event, and when the call to ReadLine completes,
fire the event. Then, you can attach any listener that you want. You just
have to be careful, because the event will be fired on the thread that is
doing the reading.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

JoKur said:
Nicholas,

Thanks for the suggestion. I had started by trying this approach but
couldn't figure out how to get the polling thread to raise a message to
the
running program. Do you have any examples/samples of this?
--
Thanks
Joe


Nicholas Paldino said:
JoKur,

What I would do is have the StreamReader run in a loop, reading lines
as
they come (it will hang in between). The key though is to have the
StreamReader run on another thread, which would raise an event when the
message is received. This way, you won't have to worry about hanging
your
application, and can get notifications when the messages come in.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

JoKur said:
Hello,

First let me tell you that I'm very new to C# and learning as I go.
I'm
trying to write a client application to communicate with a server (that
I
didn't write). Each message from the server is on one line (\r\n at
end)
and
is formed as [Message] [Optional Argument1] [Optional Argument2] - each
of
which is seperated by a space. Arguments with spaces in them are
enclosed
in
quotations.

So, I'm able to open a connection to the server. When I send a message
to
it, it immediately responds and I parse that using a
streaReader.Readline().
- That part works. The problem is that the server is also sending
status
messages every couple of seconds which seem to get lost. I didn't know
how
to have it raise an event when data is present at the stream, so I
setup a
timer to poll the stream.

I've tried using "streamReader.Peek() != null" but it hangs, I've tried
just
streamReader.ReadLine() but it hangs. Any suggestions are greatly
appreciated. I'm using Beta 2

Code is below

Thanks in advance!!
Joe


using System;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Threading;
using System.Net.Sockets;
using System.IO;

public delegate void ConnectionHandler(bool State);
public delegate void ControlChangeHandler(String Message);

public partial class MMConnection : Form
{

//--------------------------------------------------------------
// Class Variables
private NetworkStream netStream;
private StreamWriter netWriter;
private StreamReader netReader;
public TcpClient netClient;
private bool netClientStart = false;
private bool netClientConnected = false;

private System.Net.IPAddress ipAddress =
System.Net.IPAddress.Parse("127.0.0.1");
private int ipPort = 1632;
private String strUsername = "Contemporary";
private String strPassword = "techspa";
private bool blnLoggedIn = false;

// Define events this class can raise
public event ConnectionHandler OnConnectionChanged;
public event ControlChangeHandler OnControlChanged;

//--------------------------------------------------------------
// Constructor
public MMConnection()
{
InitializeComponent();
}

// Startup the client
public void ConnectionStart()
{
netClientStart = true;
tmrStatus.Enabled = true;
}

public void ConnectionStop ()
{
try
{
logToScreen("Closing connection");

// Close connection
netWriter.Close();
netReader.Close();
netStream.Close();
netClient.Close();
}
catch (Exception e)
{
logToScreen("Error closing connection: " + e.Message.ToString());
}
}

private void StreamWrite (string strMessage)
{
try
{
if (strMessage != "sg") logToScreen("Sending string: " + strMessage);
netWriter.Write(strMessage + "\r\n");
netWriter.Flush();
}
catch (Exception e)
{
netClientConnected = false; // Cannot send - client must have
disconnected
Console.WriteLine("Error sending string: " + e.Message.ToString());
}
}

public void MessageSend(string strMessage)
{
StreamWrite(strMessage);
}

// Send Password to the server
private void sendLogin()
{
StreamWrite("li" + " " + strUsername + " " + strPassword);
}

// Parse responses from the server
private void ProcessString(String strData)
{
int foundPosition; //Position of the first space
String firstToken; //The first token (command or error

// Parse out the first token
foundPosition = strData.IndexOf(@" ");
if (foundPosition > -1)
{
firstToken = strData.Substring(0, foundPosition).ToString();
}
else
{
firstToken = strData.ToString();
}

// Act on the first token
switch (firstToken)
{
case "notLoggedIn":
sendLogin();
break;

case "loggedIn":
blnLoggedIn = true;
logToScreen("Logged into MediaMatrix");
UpdateConnectionIndicator(netClient.Connected);
break;

case "statusIs":
blnLoggedIn = true;
break;

case "valueIs":
OnControlChanged(strData);
break;

default: //no token
break;
}
}

private void tmrStatus_Tick(object sender, EventArgs e)
{
if (netClientConnected)
{
tmrRead.Enabled = true;
StreamWrite("sg"); //Status Get
}
else
{
if (netClientStart)
{
try
{

netClient = new TcpClient();
// Create TcpClient and connect to server
netClient.Connect(ipAddress, ipPort);
//UpdateConnectionIndicator(netClient.Connected); //Moved to after
login

// Get network Stream associated with TcpClient
netStream = netClient.GetStream();
netClientConnected = true;
logToScreen("Connection Successfull to: " + ipAddress + " port: " +
ipPort);

// Create readers and writers
netReader = new StreamReader(netStream);
netWriter = new StreamWriter(netStream);
Console.WriteLine("Got Streams!");
}
catch (Exception error)
{
Console.Write ("Error: " + error.ToString());
netClientConnected = false;
}
}
}

// Update the color
//UpdateConnectionIndicator(netClient.Connected);
}

private void logToScreen(String strMessage)
{
lstReceive.Items.Add(strMessage);
Console.WriteLine(strMessage);
}

private void btnSend_Click(object sender, EventArgs e)
{
StreamWrite(txtSend.Text);
}

private void tmrRead_Tick(object sender, EventArgs e)
{
String strData;

try
{
// Read and display lines from the network stream
//while(netStream.DataAvailable)
// logToScreen("End of Stream: " + netReader.EndOfStream);
// logToScreen("Net Reader: " + netReader.ReadLine().ToString());
// logToScreen("End of Stream: " + netReader.EndOfStream);
while (netStream.DataAvailable)
{
try
{
// Grab data from socket
strData = netReader.ReadLine();

// Clean it up a bit
strData = strData.Trim(new char[3] { '\a', '\r', '\n' });

// Send it on to be parsed
logToScreen("Received string: " + strData);
ProcessString(strData);
}
catch (Exception ex)
{
logToScreen("Error reading string: " + ex.Message.ToString());
}
}
}
catch (Exception exc)
{
logToScreen("Error Receiving: " + exc.Message.ToString());
}
}

public static string[] Tokenize(string strIncoming)
{
//TODO: Put regular expresstion
System.Text.RegularExpressions.Regex regFilter = new
System.Text.RegularExpressions.Regex
( @"\a|\s" );

return (regFilter.Split(strIncoming));
}

private void UpdateConnectionIndicator(bool blnConnected)
{
if (blnConnected)
{
staStripConnected.Text = "Connected";
staStripConnected.BackColor = System.Drawing.Color.LightGreen;
}
else
{
staStripConnected.Text = "Not Connected";
staStripConnected.BackColor = System.Drawing.Color.Red;
}
 
J

Jon Skeet [C# MVP]

JoKur said:
It ends each line with \r\n, which is supposedly what ReadLine() looks for.
I can see this when I connect using Telnet.

I had another thought, is it possible that the server is sending more than
one line but when I'm reading them, I'm only grabbing the first line?

In other words... What happens if I'm accessing the stream (like writing to
it), when something else comes in? Is there a way to ask how many lines it
sees and then do a ReadLine() for each one?

Just calling ReadLine repeatedly should be fine. It doesn't matter if
you're writing when the line comes in - it will buffer the input.
 
G

Guest

Being as I'm so new to C#, can you give an example of this?
--
Thanks
Joe


Nicholas Paldino said:
JoKur,

Why not just create an event, and when the call to ReadLine completes,
fire the event. Then, you can attach any listener that you want. You just
have to be careful, because the event will be fired on the thread that is
doing the reading.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

JoKur said:
Nicholas,

Thanks for the suggestion. I had started by trying this approach but
couldn't figure out how to get the polling thread to raise a message to
the
running program. Do you have any examples/samples of this?
--
Thanks
Joe


Nicholas Paldino said:
JoKur,

What I would do is have the StreamReader run in a loop, reading lines
as
they come (it will hang in between). The key though is to have the
StreamReader run on another thread, which would raise an event when the
message is received. This way, you won't have to worry about hanging
your
application, and can get notifications when the messages come in.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Hello,

First let me tell you that I'm very new to C# and learning as I go.
I'm
trying to write a client application to communicate with a server (that
I
didn't write). Each message from the server is on one line (\r\n at
end)
and
is formed as [Message] [Optional Argument1] [Optional Argument2] - each
of
which is seperated by a space. Arguments with spaces in them are
enclosed
in
quotations.

So, I'm able to open a connection to the server. When I send a message
to
it, it immediately responds and I parse that using a
streaReader.Readline().
- That part works. The problem is that the server is also sending
status
messages every couple of seconds which seem to get lost. I didn't know
how
to have it raise an event when data is present at the stream, so I
setup a
timer to poll the stream.

I've tried using "streamReader.Peek() != null" but it hangs, I've tried
just
streamReader.ReadLine() but it hangs. Any suggestions are greatly
appreciated. I'm using Beta 2

Code is below

Thanks in advance!!
Joe


using System;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Threading;
using System.Net.Sockets;
using System.IO;

public delegate void ConnectionHandler(bool State);
public delegate void ControlChangeHandler(String Message);

public partial class MMConnection : Form
{

//--------------------------------------------------------------
// Class Variables
private NetworkStream netStream;
private StreamWriter netWriter;
private StreamReader netReader;
public TcpClient netClient;
private bool netClientStart = false;
private bool netClientConnected = false;

private System.Net.IPAddress ipAddress =
System.Net.IPAddress.Parse("127.0.0.1");
private int ipPort = 1632;
private String strUsername = "Contemporary";
private String strPassword = "techspa";
private bool blnLoggedIn = false;

// Define events this class can raise
public event ConnectionHandler OnConnectionChanged;
public event ControlChangeHandler OnControlChanged;

//--------------------------------------------------------------
// Constructor
public MMConnection()
{
InitializeComponent();
}

// Startup the client
public void ConnectionStart()
{
netClientStart = true;
tmrStatus.Enabled = true;
}

public void ConnectionStop ()
{
try
{
logToScreen("Closing connection");

// Close connection
netWriter.Close();
netReader.Close();
netStream.Close();
netClient.Close();
}
catch (Exception e)
{
logToScreen("Error closing connection: " + e.Message.ToString());
}
}

private void StreamWrite (string strMessage)
{
try
{
if (strMessage != "sg") logToScreen("Sending string: " + strMessage);
netWriter.Write(strMessage + "\r\n");
netWriter.Flush();
}
catch (Exception e)
{
netClientConnected = false; // Cannot send - client must have
disconnected
Console.WriteLine("Error sending string: " + e.Message.ToString());
}
}

public void MessageSend(string strMessage)
{
StreamWrite(strMessage);
}

// Send Password to the server
private void sendLogin()
{
StreamWrite("li" + " " + strUsername + " " + strPassword);
}

// Parse responses from the server
private void ProcessString(String strData)
{
int foundPosition; //Position of the first space
String firstToken; //The first token (command or error

// Parse out the first token
foundPosition = strData.IndexOf(@" ");
if (foundPosition > -1)
{
firstToken = strData.Substring(0, foundPosition).ToString();
}
else
{
firstToken = strData.ToString();
}

// Act on the first token
switch (firstToken)
{
case "notLoggedIn":
sendLogin();
break;

case "loggedIn":
blnLoggedIn = true;
logToScreen("Logged into MediaMatrix");
UpdateConnectionIndicator(netClient.Connected);
break;

case "statusIs":
blnLoggedIn = true;
break;

case "valueIs":
OnControlChanged(strData);
break;

default: //no token
break;
}
}

private void tmrStatus_Tick(object sender, EventArgs e)
{
if (netClientConnected)
{
tmrRead.Enabled = true;
StreamWrite("sg"); //Status Get
}
else
{
if (netClientStart)
{
try
{

netClient = new TcpClient();
// Create TcpClient and connect to server
netClient.Connect(ipAddress, ipPort);
//UpdateConnectionIndicator(netClient.Connected); //Moved to after
login

// Get network Stream associated with TcpClient
netStream = netClient.GetStream();
netClientConnected = true;
logToScreen("Connection Successfull to: " + ipAddress + " port: " +
ipPort);

// Create readers and writers
netReader = new StreamReader(netStream);
netWriter = new StreamWriter(netStream);
Console.WriteLine("Got Streams!");
}
catch (Exception error)
{
Console.Write ("Error: " + error.ToString());
netClientConnected = false;
}
}
}

// Update the color
//UpdateConnectionIndicator(netClient.Connected);
}

private void logToScreen(String strMessage)
{
lstReceive.Items.Add(strMessage);
Console.WriteLine(strMessage);
}

private void btnSend_Click(object sender, EventArgs e)
{
StreamWrite(txtSend.Text);
}

private void tmrRead_Tick(object sender, EventArgs e)
{
String strData;

try
{
// Read and display lines from the network stream
//while(netStream.DataAvailable)
// logToScreen("End of Stream: " + netReader.EndOfStream);
// logToScreen("Net Reader: " + netReader.ReadLine().ToString());
// logToScreen("End of Stream: " + netReader.EndOfStream);
while (netStream.DataAvailable)
{
try
{
// Grab data from socket
strData = netReader.ReadLine();

// Clean it up a bit
strData = strData.Trim(new char[3] { '\a', '\r', '\n' });

// Send it on to be parsed
 
G

Guest

I thought it should be fine too, but ReadLine() hangs when there's no data
currently in the stream. Any suggestions?
 
J

Jon Skeet [C# MVP]

JoKur said:
I thought it should be fine too, but ReadLine() hangs when there's no data
currently in the stream. Any suggestions?

It's *meant* to block when there's no data in the stream. I don't see
why that's a problem - if it is, then it sounds like you need to
process the incoming stream in another thread.
 
G

Guest

Sorry, maybe I'm too much of a newbie to understand what you mean by 'block'.
What happens is the app just freezes (without throwing any exception) when
there is no data. It never resumes, even when new data has been put into the
stream.

The help file on StreamReader.ReadLine() says to do this...

using (StreamReader sr = new StreamReader(path))
{
while (sr.Peek() >= 0)
{
Console.WriteLine(sr.ReadLine());
}
}

When I try to use Peek(), it hang too. Same thing - never resumes, just
freezes right there. So, are the StreamReaders meant to be used with
TCPClient? If not, how should I change my app to make these things work?

If what your saying is true, and these functions are performing as they are
'meant' to, then I'll have to sense when the tread is hung and start a new
thread? Is that right? ...and if I'm starting a new thread everytime one
hangs (which will be about 10 X per second) what happens to the old threads?
(isn't that somewhat like a memory leak?).

Thank you for your time, I'm just so confused!!
 
J

Jon Skeet [C# MVP]

JoKur said:
Sorry, maybe I'm too much of a newbie to understand what you mean by 'block'.
What happens is the app just freezes (without throwing any exception) when
there is no data. It never resumes, even when new data has been put into the
stream.

If a line ending has gone into the stream (and been flushed
appropriately), it should definitely read that.
The help file on StreamReader.ReadLine() says to do this...

using (StreamReader sr = new StreamReader(path))
{
while (sr.Peek() >= 0)
{
Console.WriteLine(sr.ReadLine());
}
}

I'd avoid using Peek myself. Instead, use the fact that ReadLine
returns null when it's finished.
When I try to use Peek(), it hang too. Same thing - never resumes, just
freezes right there. So, are the StreamReaders meant to be used with
TCPClient? If not, how should I change my app to make these things work?

It sounds like the server isn't flushing data or something similar.
If what your saying is true, and these functions are performing as they are
'meant' to, then I'll have to sense when the tread is hung and start a new
thread? Is that right? ...and if I'm starting a new thread everytime one
hangs (which will be about 10 X per second) what happens to the old threads?
(isn't that somewhat like a memory leak?).

You'll be leaking threads - definitely not a good idea. It really
sounds like the server isn't behaving as you expect it to. You should
hook up a network monitor to see what's coming back.
 
C

Cool Guy

JoKur said:
If what your saying is true, and these functions are performing as they are
'meant' to, then I'll have to sense when the tread is hung and start a new
thread? Is that right? ...and if I'm starting a new thread everytime one
hangs (which will be about 10 X per second) what happens to the old threads?
(isn't that somewhat like a memory leak?).

The problem with your current approach is that, since you call
StreamReader.ReadLine in the main (GUI) thread, the GUI will freeze when
there isn't currently a line to be read (ReadLine halts execution of the
thread on which it was called until there's a line to be read).

One way of solving this problem would be to create a background thread and
call ReadLine in that, over and over until the application has been closed,
notifying the GUI thread of data arrival via events. Then if ReadLine
doesn't return immediately, your GUI will not freeze.

I'd recommend that you read this:
<http://www.pobox.com/~skeet/csharp/threads/>.
 
G

Guest

Thanks, that's what Nicholas was suggesting also. The problem is I don't
know how to do that. Can you give me an example of creating a thread and
having it raise events? ...or at least point me to some more reading?
 
G

Guest

Thanks for everyone's help. It's closer but still not working. I've done a
lot of reading, testing and rewriting. I verified the problem is not on the
server by writing a test app in VB6 which works fine (win sock raises events
when there's data present).

Below is my latest code. The main app instantiates the SharedBuffer twice,
one for incoming and one for outgoing. That way, the read/write thread can
be completely independant. (The read and write were in seperate threads once
but that actually worked not as well).

Now, I can send a bunch of strings out but the response to each one only
comes back several seconds later (they all come it at once). I'm guessing
that the "DataAvailable" property is the culprit of that. Removing the
DataAvailable check makes it worse though, the readline() hangs for longer
before returning anything. Then, when it returns it has 5-10 lines that it
reads.

At this point, I've been working on this way too long. Please, can somebody
help?? I have a Paypal account and I'm not afraid to use it!

Thanks
Joe


using System;
using System.Collections;
using System.Text;
using System.IO;
using System.Threading;
using System.Net.Sockets;

public class SharedBuffer
{
private ArrayList myBuffer = new ArrayList (1);
private String myName = null;

// constructor
public SharedBuffer()
{
}

public void Add (String strIncoming)
{
// lock this object while setting value in buffers array
lock (this)
{
myBuffer.Insert(0, strIncoming);

// For debugging
Console.WriteLine(myName + ": " + CreateStateOutput());

} // end lock
} // end property Add

public bool DataAvailable
{
get
{
// Return the count of the current array list
if (myBuffer.Count > 0) { return true; }
else { return false; };
} // end accessor set
}

public String Name
{
set
{
myName = value;
} // end accessor set
}

public String Remove ()
{
String strData;

// lock this object while setting value in buffers array
lock (this)
{
if (myBuffer.Count > 0)
{
strData = myBuffer[myBuffer.Count - 1].ToString();

// Delete the last element
myBuffer.RemoveAt(myBuffer.Count - 1);

// For debugging
Console.WriteLine(myName + ": " + CreateStateOutput());
}
else
{
strData = null;
}

} // end lock

return strData;

} // end property Remove




private String CreateStateOutput() // Displays current buffer
{
String strOutput = null; //Holds the output display

// display first line of state information
strOutput = "\r\nBuffer Status... \r\n";

// Show the contents of each buffer
for (int i = 0; i < myBuffer.Count; i++) strOutput += i + ") " +
myBuffer + "\r\n";

return strOutput;
}

} // end class SharedBuffer



public class StreamManager //Poll the stream for new messages
{
// Establish network objects
public TcpClient netClient;
private NetworkStream netStream; // local copy of the network stream
private StreamReader netReader; // local copy of the stream reader
private StreamWriter netWriter;

// Establish network variables
private System.Net.IPAddress ipAddress;
private int ipPort = 1632;
private bool blnStarted; // desired state of the reading thread

private SharedBuffer strBufferReceive; // buffer to put the received
strings into
private SharedBuffer strBufferSend; // buffer to put the received strings
into

// constructor
public StreamManager(System.Net.IPAddress myIP, Int16 myPort, SharedBuffer
myIncomingBuffer, SharedBuffer myOutgoingBuffer)
{
ipAddress = myIP;
ipPort = myPort;
strBufferReceive = myIncomingBuffer;
strBufferSend = myOutgoingBuffer;
}

public void Disconnect()
{
blnStarted = false;
}

// Startup the client
public void Connect()
{
try
{
// Create TcpClient and connect to server
netClient = new TcpClient();
netClient.Connect(ipAddress, ipPort);

// Get network Stream associated with TcpClient
netStream = netClient.GetStream();
blnStarted = true;
Console.WriteLine("Connection Successfull to: " + ipAddress + " port: " +
ipPort);

// Create readers and writers
netReader = new StreamReader(netStream);
netWriter = new StreamWriter(netStream);
Console.WriteLine("Got Streams!");

blnStarted = true;
ReadWrite();
}
catch(Exception ex)
{
Console.WriteLine("Error: " + ex.Message.ToString());
}
}


// Read lines from the stream and raise events returning them
private void ReadWrite()
{
String[] Tokens;
String strData = null;

while (blnStarted)
{
//Do some reading

if (netStream.CanRead && netStream.DataAvailable)
{
try
{
// Grab data from socket
strData = netReader.ReadLine();

// Clean it up a bit
strData = strData.Trim(new char[3] { '\a', '\r', '\n' });
strBufferReceive.Add(strData);
}
catch (Exception ex)
{
Console.WriteLine("Error reading from port or saving to buffer... \r\n
" + ex.Message.ToString());
}
}

//Do some writing
while (strBufferSend.DataAvailable)
{
try
{
// Grab data from buffer and send it
//if (strMessage != "sg") logToScreen("Sending string: " + strMessage);
strData = strBufferSend.Remove();
Console.WriteLine("StreamManager sending string: " + strData);
netWriter.Write(strData + "\r\n");
netWriter.Flush();
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show("Error reading from send buffer or
sending it out port... \r\n" + ex.Message.ToString());
}

} // End write

} // end while started
}



private String[] Tokenize(String strIncoming)
{
String[] strTokens;

strTokens = System.Text.RegularExpressions.Regex.Split(strIncoming,
@"\n|\r");

return strTokens;
}

} // end class StreamManager
 
C

Cool Guy

JoKur said:
Can you give me an example of creating a thread and
having it raise events?

Following is a small, very simple example of using a worker thread in a
console application. Before you consider using worker threads with forms
(where things aren't so simple), you'll need to be sure that you understand
this example *entirely*.

-----

using System;
using System.Threading;

namespace Threading
{
class EntryPoint
{
[STAThread]
static void Main() {
Worker worker = new Worker();
worker.GotData += new GotDataEventHandler(worker_GotData);
worker.Start();
}

static void worker_GotData(int data) {
Console.WriteLine("Got data: {0}.", data);
}
}

class Worker
{
public void Start() {
// note: no need to keep reference to Thread instance here --
// we don't need it, and the GC won't collect the instance
// until the underlying thread has finished executing
new Thread(new ThreadStart(ThreadJob)).Start();
}

void ThreadJob() {
for (int i = 0; i < 10; ++i) {
// simulate doing some work which blocks execution
Thread.Sleep(500);
// send dummy data back
int dummyData = new Random().Next(1, 101);
if (GotData != null) {
GotData(dummyData);
}
}
}

public event GotDataEventHandler GotData;
}

delegate void GotDataEventHandler(int data);
}

-----

After understanding this example, you'd then really need to read and
understand Jon's article on threading (which I linked to previously) before
you're ready to consider moving onto implementing a multi-threaded GUI
application.
 
C

Cool Guy

JoKur said:
Removing the
DataAvailable check makes it worse though, the readline() hangs for longer
before returning anything.

If NetworkStream.DataAvailable is true, it doesn't necessarily mean that *a
whole line* is available to be read.

If a whole line is not available to be read, a call to
StreamReader.ReadLine will block until one *is* available.

You really should be doing this in a way that doesn't block the GUI thread.
For example: by calling StreamReader.ReadLine in a *worker thread* instead.
 
G

Guest

Thanks!
I got the thread running and it works better. But some responses still get
lost. When I'm wriiting to the socket, does it block responses?
 
C

Cool Guy

JoKur said:
I got the thread running and it works better. But some responses still get
lost.

Just to check: you are logging (via Console.WriteLine, Trace.WriteLine, or
whatever) the result of each call to StreamReader.ReadLine, in order to
determine what you're actually reading -- right?
When I'm wriiting to the socket, does it block responses?

Only if the thread that you're writing in is the same thread as the one
that you're reading in. In this case, the reading would get delayed until
after the writing has completed -- and the writing would get delayed until
after the reading has completed (i.e.: while you're waiting for
StreamReader.ReadLine to complete, you can't write).

If you're reading in one thread and writing in another, neither operation
will block the other.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top