question about multithread c# socket server

G

Guest

Hello:
I write a multithread c# socket server,it is a winform application,there is a richtextbox control and button,when the button is click,the server begin to listen the socket port,waiting for a incoming connection,the relative code snipprt as following::

private IPAddress myIP=IPAddress.Parse("127.0.0.1");
private IPEndPoint myServer;
private Socket socket;
private Socket accSocket;
private System.Windows.Forms.Button button2;
private bool check;

private void button1_Click(object sender, System.EventArgs e)
{
check=true;
try
{
Thread thread =new Thread(new ThreadStart(accp));
thread.Start();
}
catch(Exception ee)
{
MessageBox.Show(ee.Message);
}
}

private void accp()
{
myServer=new IPEndPoint(myIP,Int32.Parse("20000"));
socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
socket.Bind(myServer);
socket.Listen(50);

while(true)
{
try
{
accSocket=socket.Accept();
if(accSocket.Connected)
{
Thread thread=new Thread(new ThreadStart(round));
thread.Start();
}
}
catch(Exception ee)
{
MessageBox.Show(ee.Message);
}
}
}

private void round()
{

Byte[] rec=new Byte[1024];
NetworkStream acceptStream=new NetworkStream(accSocket);

int i=0;
while((i=acceptStream.Read(rec,0,rec.Length))!=0)
{
string recMessage=System.Text.Encoding.Default.GetString(rec);
rec=new Byte[1024];
this.richTextBox1.AppendText(recMessage);
}

}
……………………………………….
………………………………………




In order to test the server,I write a multithread client too,there is only one button in the form,when it is clicked,four threads is generated to connect the server simultaneously,each thread write one line to the server socket.code as:



private IPAddress myIP;
private IPEndPoint myServer;
private Socket socket;

private void button1_Click(object sender, System.EventArgs e)
{
for(int i=0;i<4;i++)
{
Thread thread=new Thread(new ThreadStart(round));
thread.Start();
thread.Join();
}
}

private void round()
{
try
{
myIP=IPAddress.Parse("127.0.0.1");
myServer=new IPEndPoint(myIP,Int32.Parse("20000"));
socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
socket.Connect(myServer);
NetworkStream netStream=new NetworkStream(socket);

Byte[] byteMessage=new Byte[640];
string sendMessage="大家好ï¼ï¼ï¼ï¼!\r\n";
byteMessage=System.Text.Encoding.Default.GetBytes(sendMessage.ToCharArray());
// socket.Send(byteMessage,byteMessage.Length,0);
netStream.Write(byteMessage,0,byteMessage.Length);
netStream.Flush();
netStream.Close();
socket.Close();
}
catch(Exception ee)
{
MessageBox.Show(ee.Message);
}

}



As you can see,when I click the button in the client side,I should see four lines is printed in the server side.but in fact,I can’t,I can only see one line,sometimes two or three lines,by my tracing,I found they always come from the last several threads.if I modify the button click event in the client as following(add sleep between the threads),it works well,that is I can see four lines every time in the server:


private void button1_Click(object sender, System.EventArgs e)
{
for(int i=0;i<4;i++)
{
Thread thread=new Thread(new ThreadStart(round));
thread.Start();
thread.Join();
Thread.Sleep(100);
}
}

If I modify the timeout param of the sleep method to lower and lower, the mentioned problem occur again.i also write a java multithread server, it works well to the simuteneous thread connection.
Why c# socket server can’t handle the simultaneous access?is it a bug?by comparing the java server and c# server,I also found that the java server is faster then c# server.

Any instruction?Thank you.
 
H

Henrik Dahl

Hello!

For instance you don't respect that the rich text box may only be dealt with
by the STA thread which created it.

Have you generally considered to use asynchronous sockets instead of your
own explicit thread handling?


Best regards,

Henrik Dahl

zbcong said:
Hello:
I write a multithread c# socket server,it is a winform application,there
is a richtextbox control and button,when the button is click,the server
begin to listen the socket port,waiting for a incoming connection,the
relative code snipprt as following::
private IPAddress myIP=IPAddress.Parse("127.0.0.1");
private IPEndPoint myServer;
private Socket socket;
private Socket accSocket;
private System.Windows.Forms.Button button2;
private bool check;

private void button1_Click(object sender, System.EventArgs e)
{
check=true;
try
{
Thread thread =new Thread(new ThreadStart(accp));
thread.Start();
}
catch(Exception ee)
{
MessageBox.Show(ee.Message);
}
}

private void accp()
{
myServer=new IPEndPoint(myIP,Int32.Parse("20000"));
socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
socket.Bind(myServer);
socket.Listen(50);

while(true)
{
try
{
accSocket=socket.Accept();
if(accSocket.Connected)
{
Thread thread=new Thread(new ThreadStart(round));
thread.Start();
}
}
catch(Exception ee)
{
MessageBox.Show(ee.Message);
}
}
}

private void round()
{

Byte[] rec=new Byte[1024];
NetworkStream acceptStream=new NetworkStream(accSocket);

int i=0;
while((i=acceptStream.Read(rec,0,rec.Length))!=0)
{
string recMessage=System.Text.Encoding.Default.GetString(rec);
rec=new Byte[1024];
this.richTextBox1.AppendText(recMessage);
}

}
................
...............




In order to test the server,I write a multithread client too,there is only
one button in the form,when it is clicked,four threads is generated to
connect the server simultaneously,each thread write one line to the server
socket.code as:
private IPAddress myIP;
private IPEndPoint myServer;
private Socket socket;

private void button1_Click(object sender, System.EventArgs e)
{
for(int i=0;i<4;i++)
{
Thread thread=new Thread(new ThreadStart(round));
thread.Start();
thread.Join();
}
}

private void round()
{
try
{
myIP=IPAddress.Parse("127.0.0.1");
myServer=new IPEndPoint(myIP,Int32.Parse("20000"));
socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
socket.Connect(myServer);
NetworkStream netStream=new NetworkStream(socket);

Byte[] byteMessage=new Byte[640];
string sendMessage="???!!!!!\r\n";
byteMessage=System.Text.Encoding.Default.GetBytes(sendMessage.ToCharArray())
;
// socket.Send(byteMessage,byteMessage.Length,0);
netStream.Write(byteMessage,0,byteMessage.Length);
netStream.Flush();
netStream.Close();
socket.Close();
}
catch(Exception ee)
{
MessageBox.Show(ee.Message);
}

}



As you can see,when I click the button in the client side,I should see
four lines is printed in the server side.but in fact,I can't,I can only see
one line,sometimes two or three lines,by my tracing,I found they always come
from the last several threads.if I modify the button click event in the
client as following(add sleep between the threads),it works well,that is I
can see four lines every time in the server:
private void button1_Click(object sender, System.EventArgs e)
{
for(int i=0;i<4;i++)
{
Thread thread=new Thread(new ThreadStart(round));
thread.Start();
thread.Join();
Thread.Sleep(100);
}
}

If I modify the timeout param of the sleep method to lower and lower, the
mentioned problem occur again.i also write a java multithread server, it
works well to the simuteneous thread connection.
Why c# socket server can't handle the simultaneous access?is it a bug?by
comparing the java server and c# server,I also found that the java server is
faster then c# server.
 
G

Guest

no,it is not the problem of rich text box,if you replace "richTextBox1.AppendText(recMessage)" with "Console.WriteLine(recMessage)" in the serverside,you can only see ONE line printed every time the button is clicked,why?













Henrik Dahl said:
Hello!

For instance you don't respect that the rich text box may only be dealt with
by the STA thread which created it.

Have you generally considered to use asynchronous sockets instead of your
own explicit thread handling?


Best regards,

Henrik Dahl

zbcong said:
Hello:
I write a multithread c# socket server,it is a winform application,there
is a richtextbox control and button,when the button is click,the server
begin to listen the socket port,waiting for a incoming connection,the
relative code snipprt as following::
private IPAddress myIP=IPAddress.Parse("127.0.0.1");
private IPEndPoint myServer;
private Socket socket;
private Socket accSocket;
private System.Windows.Forms.Button button2;
private bool check;

private void button1_Click(object sender, System.EventArgs e)
{
check=true;
try
{
Thread thread =new Thread(new ThreadStart(accp));
thread.Start();
}
catch(Exception ee)
{
MessageBox.Show(ee.Message);
}
}

private void accp()
{
myServer=new IPEndPoint(myIP,Int32.Parse("20000"));
socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
socket.Bind(myServer);
socket.Listen(50);

while(true)
{
try
{
accSocket=socket.Accept();
if(accSocket.Connected)
{
Thread thread=new Thread(new ThreadStart(round));
thread.Start();
}
}
catch(Exception ee)
{
MessageBox.Show(ee.Message);
}
}
}

private void round()
{

Byte[] rec=new Byte[1024];
NetworkStream acceptStream=new NetworkStream(accSocket);

int i=0;
while((i=acceptStream.Read(rec,0,rec.Length))!=0)
{
string recMessage=System.Text.Encoding.Default.GetString(rec);
rec=new Byte[1024];
this.richTextBox1.AppendText(recMessage);
}

}
................
...............




In order to test the server,I write a multithread client too,there is only
one button in the form,when it is clicked,four threads is generated to
connect the server simultaneously,each thread write one line to the server
socket.code as:
private IPAddress myIP;
private IPEndPoint myServer;
private Socket socket;

private void button1_Click(object sender, System.EventArgs e)
{
for(int i=0;i<4;i++)
{
Thread thread=new Thread(new ThreadStart(round));
thread.Start();
thread.Join();
}
}

private void round()
{
try
{
myIP=IPAddress.Parse("127.0.0.1");
myServer=new IPEndPoint(myIP,Int32.Parse("20000"));
socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
socket.Connect(myServer);
NetworkStream netStream=new NetworkStream(socket);

Byte[] byteMessage=new Byte[640];
string sendMessage="???!!!!!\r\n";
byteMessage=System.Text.Encoding.Default.GetBytes(sendMessage.ToCharArray())
;
// socket.Send(byteMessage,byteMessage.Length,0);
netStream.Write(byteMessage,0,byteMessage.Length);
netStream.Flush();
netStream.Close();
socket.Close();
}
catch(Exception ee)
{
MessageBox.Show(ee.Message);
}

}



As you can see,when I click the button in the client side,I should see
four lines is printed in the server side.but in fact,I can't,I can only see
one line,sometimes two or three lines,by my tracing,I found they always come
from the last several threads.if I modify the button click event in the
client as following(add sleep between the threads),it works well,that is I
can see four lines every time in the server:
private void button1_Click(object sender, System.EventArgs e)
{
for(int i=0;i<4;i++)
{
Thread thread=new Thread(new ThreadStart(round));
thread.Start();
thread.Join();
Thread.Sleep(100);
}
}

If I modify the timeout param of the sleep method to lower and lower, the
mentioned problem occur again.i also write a java multithread server, it
works well to the simuteneous thread connection.
Why c# socket server can't handle the simultaneous access?is it a bug?by
comparing the java server and c# server,I also found that the java server is
faster then c# server.
Any instruction?Thank you.
 
D

David Logan

zbcong said:
no,it is not the problem of rich text box,if you replace "richTextBox1.AppendText(recMessage)" with "Console.WriteLine(recMessage)" in the serverside,you can only see ONE line printed every time the button is clicked,why?

No, it is not the problem of the rich text box. As the previous response
said, it is the problem of thread safety. The RTB is not threadsafe, and
must be updated in the thread that created the RTB only.
Console.WriteLine() is threadsafe. Thus you get what you expect. What
you need is a way to update in the creating thread:
class MyForm:Form
{
public void Append(String msg)
{
if( InvokeRequired )
BeginInvoke(new MyDelegate(InvokedAppendFunc),
new object[] {msg});
else
DoAppend(msg);
}
private void InvokedAppendFunc(String msg)
{
DoAppend(msg);
}
private void DoAppend(String msg)
{
richtextbox1.Append(msg);
}

A simple locking wouldn't work:
lock(richtextbox1)
richtextbox1.Append(msg);

because none of the code in the RTB does this, and you need threadsafety
support to make it work. So the above Invoke procedure is the only way.

Also, consider the previous posters async socket suggestion. It uses
threads under the covers, and you do not need any explicit thread
management (other than remembering you are in a subthread and need to
keep thread safety in mind.)

David Logan
:

Hello!

For instance you don't respect that the rich text box may only be dealt with
by the STA thread which created it.

Have you generally considered to use asynchronous sockets instead of your
own explicit thread handling?


Best regards,

Henrik Dahl

Hello:
I write a multithread c# socket server,it is a winform application,there

is a richtextbox control and button,when the button is click,the server
begin to listen the socket port,waiting for a incoming connection,the
relative code snipprt as following::
private IPAddress myIP=IPAddress.Parse("127.0.0.1");
private IPEndPoint myServer;
private Socket socket;
private Socket accSocket;
private System.Windows.Forms.Button button2;
private bool check;

private void button1_Click(object sender, System.EventArgs e)
{
check=true;
try
{
Thread thread =new Thread(new ThreadStart(accp));
thread.Start();
}
catch(Exception ee)
{
MessageBox.Show(ee.Message);
}
}

private void accp()
{
myServer=new IPEndPoint(myIP,Int32.Parse("20000"));
socket=new
Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);

socket.Bind(myServer);
socket.Listen(50);

while(true)
{
try
{
accSocket=socket.Accept();
if(accSocket.Connected)
{
Thread thread=new Thread(new ThreadStart(round));
thread.Start();
}
}
catch(Exception ee)
{
MessageBox.Show(ee.Message);
}
}
}

private void round()
{

Byte[] rec=new Byte[1024];
NetworkStream acceptStream=new NetworkStream(accSocket);

int i=0;
while((i=acceptStream.Read(rec,0,rec.Length))!=0)
{
string recMessage=System.Text.Encoding.Default.GetString(rec);
rec=new Byte[1024];
this.richTextBox1.AppendText(recMessage);
}

}
................
...............




In order to test the server,I write a multithread client too,there is only

one button in the form,when it is clicked,four threads is generated to
connect the server simultaneously,each thread write one line to the server
socket.code as:
private IPAddress myIP;
private IPEndPoint myServer;
private Socket socket;

private void button1_Click(object sender, System.EventArgs e)
{
for(int i=0;i<4;i++)
{
Thread thread=new Thread(new ThreadStart(round));
thread.Start();
thread.Join();
}
}

private void round()
{
try
{
myIP=IPAddress.Parse("127.0.0.1");
myServer=new IPEndPoint(myIP,Int32.Parse("20000"));
socket=new
Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);

socket.Connect(myServer);
NetworkStream netStream=new NetworkStream(socket);

Byte[] byteMessage=new Byte[640];
string sendMessage="???!!!!!\r\n";

byteMessage=System.Text.Encoding.Default.GetBytes(sendMessage.ToCharArray())
;

// socket.Send(byteMessage,byteMessage.Length,0);
netStream.Write(byteMessage,0,byteMessage.Length);
netStream.Flush();
netStream.Close();
socket.Close();
}
catch(Exception ee)
{
MessageBox.Show(ee.Message);
}

}



As you can see,when I click the button in the client side,I should see

four lines is printed in the server side.but in fact,I can't,I can only see
one line,sometimes two or three lines,by my tracing,I found they always come
from the last several threads.if I modify the button click event in the
client as following(add sleep between the threads),it works well,that is I
can see four lines every time in the server:
private void button1_Click(object sender, System.EventArgs e)
{
for(int i=0;i<4;i++)
{
Thread thread=new Thread(new ThreadStart(round));
thread.Start();
thread.Join();
Thread.Sleep(100);
}
}

If I modify the timeout param of the sleep method to lower and lower, the

mentioned problem occur again.i also write a java multithread server, it
works well to the simuteneous thread connection.
Why c# socket server can't handle the simultaneous access?is it a bug?by

comparing the java server and c# server,I also found that the java server is
faster then c# server.
Any instruction?Thank you.
 
S

Sunny

Hi,

I haven't worked with sockets, but your server is not thread safe at
all.

Please, read inline:

private void accp()
{
myServer=new IPEndPoint(myIP,Int32.Parse("20000"));
socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
socket.Bind(myServer);
socket.Listen(50);

while(true)
{
try
{
accSocket=socket.Accept();

1. now here you set a field variable accSocket to the current accepted
socket. And start a thread which deals it that variable. And then you go
to grab the next accepted socket. And you may get it even before the
working thread is started. And you replace the same variable, so the
working method in the started thread will see the new connected socket,
not the previous one, for which was started.
if(accSocket.Connected)
{
Thread thread=new Thread(new ThreadStart(round));
thread.Start();
}
}
catch(Exception ee)
{
MessageBox.Show(ee.Message);
}
}
}

private void round()
{

Byte[] rec=new Byte[1024];
NetworkStream acceptStream=new NetworkStream(accSocket);

??? what exact connection you are dealing with here? With this
implementation you are always using the last accepted one in the other
thread.

int i=0;
while((i=acceptStream.Read(rec,0,rec.Length))!=0)
{
string recMessage=System.Text.Encoding.Default.GetString(rec);
rec=new Byte[1024];
this.richTextBox1.AppendText(recMessage);
}

}

You can make your server thread safe either by using the async socket
handling, by something like this:


class SocketReadingThread
{
private readonly Socket accSocket;

public SocketReadingThread(Socket acceptedSocket)
{
this.accSocket = acceptedSocket;
}

public void Rount()
{
..... your implementation goes here
}
}

There is a possible memory leak as well, I do not see where you close
the accepted socket or the NetworkStream.

Also, as others have mentioned, you can not write directly in the RTB
from different threads. All windows controls are not thread safe. You
have to use the Invoke method from the threads, so the writing is
correct.

Ion Skeet has a wonderful article about threads. I wish he had wrote 1
year ago ... :)

http://www.yoda.arachsys.com/csharp/multithreading.html

Sunny
 

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