Simple Echo Server
I am using Visual J# 2005 Express Beta 2 to create a simple echo server. I have created the form and design and able am able to launch the program. I have created a RichTextbox to display the connections and 'echo's. The problem is when after starting the echo server by clicking on a button, the program stops responding. But the echo server is running in the background because I am able to connect to the echo server (localhost/port with telnet) and am able to "echo" messages. After the the telnet connection to the Echo Server is closed, the Echo server program starts responding and displays all the messages in the RichTextBox. And am able to start the echo server again. The program works and ends cleanly, but I want to be able to see the connections and echos as they are occuring
How can I get the echo server to show messages while the echo server is running and connections are coming in?
Does anyone have a sample code?
Below is a snippet from my button method. (I can also provide my complete code.)
privatevoid button2_Click(Object sender,System.EventArgs e){
richTextBox1.AppendText("EchoServer started. \n");
try{
ServerSocket s =newServerSocket(8008);
Socket incoming = s.accept();
richTextBox1.AppendText("Connected to: " + incoming.getInetAddress() +" at port: " + incoming.getLocalPort() +"\n");
BufferedReader in =newBufferedReader(newInputStreamReader(incoming.getInputStream()));
PrintWriter out =newPrintWriter(newOutputStreamWriter(incoming.getOutputStream()));
out.println("Hello! This is Java EchoServer. Enter BYE to exit.");
out.flush();
for (; ; )
{
String str = in.readLine();
if (str ==null)
{
break;
}
else
{
out.println("Echo: " + str);
out.flush();
richTextBox1.AppendText("Received: " + str +"\n");
if (str.trim().equals("BYE"))
break;
}
}
incoming.close();
}
catch (Exception err)
{
richTextBox1.AppendText("Error: " + err +"\n");
}
richTextBox1.AppendText("EchoServer stopped.\n");
}
Thanks,
kihtap
[4677 byte] By [
kihap] at [2008-2-16]
Hi,
Your problem is that you are doing everything in the main thread (that's what i could make out from your problem description). The UI thread should not have any blocking/waiting or CPU instensive tasks because it makes UI nonresponsive. To avoid nonresponsiveness, do your server job in a seperate thread and keep UI thread (main thread) as free as possible.
You can create a new thread using System.Threading.Thread class. For ex...
System
.Threading.Thread thrd = new System.Threading.Thread(ThreadStartFunc);
thrd.Start();
Then inside ThreadStartFunc do your server job. To update the textBox from this thread you can use textBox.BeginInvoke(). PLease post back if still you face any issues.
Thanks.
Thanks for your help, but I am not able to run the program--
I created a new method ThreadStartFunc -->
public void ThreadStartFunc() throws InterruptedException
{
// code...
}
and right underneath it I have the button code -->
private void button1_Click(Object sender, System.EventArgs e){
System.Threading.Thread thrd = new System.Threading.Thread(ThreadStartFunc);
thrd.Start();
}But I keep getting this error:
Error 1 Name 'ThreadStartFunc' is not defined in current context
I added
"public System.Threading.Thread ThreadStartFunc;"
at the begining of my class right underneath the form button/textbox declarations, and the I get the following error.
Error 1 Cannot find constructor 'System.Threading.Thread(System.Threading.Thread)'
I also added "import System.Threading.*;" but am still getting the Error 1 Cannot find constructor 'System.Threading.Thread(System.Threading.Thread)' error.
Have I not created the methods properly?
Also I didn't follow where and how I should place the "textBox.BeginInvoke()."
Thanks.
OOps, you need to pass an instance of System.Threading.ThreadStart delegate to the constructor of System.Threading.Thread class as shown below...public void Func1() {
System.Threading.Thread thread = new System.Threading.Thread(new
System.Threading.ThreadStart(Func2));
}
public void Func2() { }
You will need to call "textBox.BeginInvoke()." inside Func2 to update the textbox control. You cannot update UI controls from any thread other than the Main window thread.
To know more about BeginInvoke please refer this link.Thanks.
Okay this is what I have now:
I added "private delegate void RichTextBoxUpdateEventHandler(String message);"
in my class.In my button method I have:
private void button1_Click(Object sender, System.EventArgs e)
{
System.Threading.Thread thrd = new System.Threading.Thread(new
System.Threading.ThreadStart(ThreadStartFunc));
thrd.Start();
}I have my ThredStartFunc->
public void ThreadStartFunc() throws InterruptedException
{
...code...
String messageToLog = "MultiEchoServer started.";
UpdateRichTextBox(messageToLog);
...code...
}
I created a new method to handle data passed to the rich text box:
private void UpdateRichTextBox(String message)
{
richTextBox1.BeginInvoke(
new RichTextBoxUpdateEventHandler(UpdateRichTextBox), // the method to call
new Object[] { message } // the list of arguments to pass );
}
But I get an error message that BeginInvoke is not called properly:
Error 1 Cannot find method 'BeginInvoke(RichTextBoxUpdateEventHandler, Object[])' in 'System.Windows.Forms.RichTextBox'
BeginInvoke is defined as-- BeginInvoke(System.Delegate method, Object[] args)
That is what I have written, RichTextBoxUpdateEventHandler, is a delegate defined in the class.
Why is this not working?
OK, in J# one need to add delegate attribute before declaration of the delegate as i have done in the following lines...
/** @delegate */
private delegate void RichTextBoxUpdateEventHandler(String message);"It should work for you now. Feel free to post back if you hit any other issue.
Thanks,
Jaiprakash
Kihtap, I suggest you to have separate thread for Server and separate thread for each client request. Following is the code sample to depict my point
public void ThreadStartFunc()
{
// Process client's request here
}
public void StartServer()
{
try
{
s = new ServerSocket(8008);
while (true)
{
incoming = s.accept();
System.Threading.Thread thrd = new
System.Threading.Thread(new ThreadStart(ThreadStartFunc));
thrd.Start();
}
}
catch (System.Exception ex)
{
// handle exception
}
richTextBox1.AppendText("EchoServer stopped.\n");
}
private void button1_Click(Object sender, System.EventArgs e)
{
richTextBox1.AppendText("EchoServer started. \n");
try
{
System.Threading.Thread thrd = new
System.Threading.Thread(new ThreadStart(StartServer));
thrd.Start();
}
catch (Exception err)
{
// handle exception
}
}
If there are multiple connects then you might need to take care of synchronizing textbox.
I am trying to incorporate the information you gave me. Its kind of difficult to debug when the UI is not responding, so its hard to tell where its stuck.
I wanted to know you are passing the new connection (incoming) to the new thread (thrd) in your StartServer ex:
while (true)
{
incoming = s.accept();
System.Threading.Thread thrd = new
System.Threading.Thread(new ThreadStart(ThreadStartFunc));
thrd.Start();
}
Should I make a new class the handles the thread? And If I do that will I still be able to write back to the UI richTextbox from the other class?
Thanks for all help.
Hi,
Is your UI still hanging after using the pattern suggested by Ramakrishna? It should not hang now.
You are free to create as many classes as you feel required. Only thing to remember is taht if you want to update the textbox from any thread other than the thread which created the textbox then you have to use textBox.BeginInvoke(). That's what we have discussed before also.
Thanks.