.NET Framework Bookmark and Share   
 index > Network Class Library (System.Net) > Is this Server Efficent (Listening Method)- Case1
 

Is this Server Efficent (Listening Method)- Case1

Hi i currently am developing an application in which a server receives a no of connections from different clients aprroximately 20
and for each client an infinite looped thread is created which is mainly responsible for checking if the client is sending something to the server.
Now if i run more than two thread my system slows down .. Is it because of the threads ?? so is there anyway by which i can control threads i.e make them less heavy on my system. ?? Some one said that I should make them event driven , any ideas + hints + suggestion how i can accomplish that?? this issue is making me crazy!!!

Private Sub GetData(ByVal x As Integer) '''''''''''''''''''''This thread waits for data from the connected clients
Dim myno As Integer
Console.WriteLine("Listening For Incoming Data on " & x & " Connection")
RETRY:
Try
If client(x).GetStream.DataAvailable = True Then
Dim Buffer(client(x).ReceiveBufferSize) As Byte
myno = client(x).GetStream.Read(Buffer, 0, CInt(client(x).ReceiveBufferSize))
If myno <> 0 And myno <> -1 Then
MsgBox("Received Data")
Dim mystring As String
mystring = Encoding.ASCII.GetString(Buffer)
MsgBox(mystring)
' Console.WriteLine(x & ":" & mystring)
End If
Else
'Do Nothing
End If
Catch ex As Exception
MsgBox(ex.Message)
End Try
GoTo RETRY
End Sub

Any help or advice would be appreciated into managing threads
A candle loses nothing by lighting another candle.
  •  
Silver_Gates
With your current design, each thread constantly requires the attention of the processor to check DataAvailable. The more threads you have constantly using the processor, the less time the processor has to do other work.

A couple suggestions:

1. Don't call DataAvailable. If no data is available, Read will wait until there is data to be read. It does this in an efficient way which doesn't use the processor, unlike constantly calling DataAvailable. You will still have 20 threads going, but each thread will only need the attention of the processor when there is actually data to be handled.

2. Convert to a completely asynchronous model, using BeginRead instead of Read. Using the async pattern, you don't create a thread for each client. Instead, you call BeginRead from your application's main thread as soon as you accept the connection. BeginRead returns immediately, so the main thread can continue waiting for new connections. When data arrives, the framework will use a ThreadPool thread to run the method you passed as the callback parameter to BeginRead. This allows your server to handle thousands of clients without having to create a separate thread for each one.

(1) may be sufficient foryour simple 20-client system. If not, make the switch to (2).

You can also save some time by reusing the buffer you pass to Read instead of allocating a new one every time. This won't make a big difference if your message rates are low, but can become a big deal if clients start sending lots of data.

-dave
  • Marked As Answer bySilver_Gates Tuesday, September 01, 2009 12:30 AM
  •  
Dave Murray [NCL]

This loop that you have here is a busy loop, which is going to spin forever waiting for data to be ready.

In order to make this server scalable, you should convert it to an asynchronous pattern. See examples in MSDN of how to implement asynchronous reads on a network stream.


feroze
--
My blog
Feroze Daud
asynchronous pattern ?? could you explain a little ?? Do u mean i should use non blocking sockets??/

A candle loses nothing by lighting another candle.
Silver_Gates
With your current design, each thread constantly requires the attention of the processor to check DataAvailable. The more threads you have constantly using the processor, the less time the processor has to do other work.

A couple suggestions:

1. Don't call DataAvailable. If no data is available, Read will wait until there is data to be read. It does this in an efficient way which doesn't use the processor, unlike constantly calling DataAvailable. You will still have 20 threads going, but each thread will only need the attention of the processor when there is actually data to be handled.

2. Convert to a completely asynchronous model, using BeginRead instead of Read. Using the async pattern, you don't create a thread for each client. Instead, you call BeginRead from your application's main thread as soon as you accept the connection. BeginRead returns immediately, so the main thread can continue waiting for new connections. When data arrives, the framework will use a ThreadPool thread to run the method you passed as the callback parameter to BeginRead. This allows your server to handle thousands of clients without having to create a separate thread for each one.

(1) may be sufficient foryour simple 20-client system. If not, make the switch to (2).

You can also save some time by reusing the buffer you pass to Read instead of allocating a new one every time. This won't make a big difference if your message rates are low, but can become a big deal if clients start sending lots of data.

-dave
  • Marked As Answer bySilver_Gates Tuesday, September 01, 2009 12:30 AM
  •  
Dave Murray [NCL]
That's what you mean by event-driven. Try using BeginRead method instead of Read method.
http://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.beginread.aspx


You just pass the delegate which must envoke EndRead to receive the same data as would be otherwise returned by Read. The framework should handle all multithreading for you.
Oleksii Prokopchuk [NCL]

@Dave Murray [NCL]
Thanks man for the great advise.. you definitely saved me.
Anyways so I readjusted the above code which i had posted ,to the following new code

Private Sub GetData(ByVal x As Integer) 'My Never ending Thread :)
Dim myno As Integer
Dim File_Name As String
Dim ShortString As String
Console.WriteLine("Listening For Incoming Data on " & x & " Connection")
RETRY:
Try
If client(x).Client.Connected = True Then
Dim Buffer(client(x).ReceiveBufferSize) As Byte
myno = client(x).GetStream.Read(Buffer, 0, CInt(client(x).ReceiveBufferSize))
If myno <> 0 And myno <> -1 Then
ShortString = Encoding.ASCII.GetString(Buffer, 0, myno)
'################################################
Dim fsstream As System.IO.FileStream
Dim bwwriter As System.IO.BinaryWriter

Dim MyArray() As String
ShortString = Encoding.ASCII.GetString(Buffer, 0, myno)
MsgBox(ShortString)

If Microsoft.VisualBasic.Left(ShortString, 6) = "#Make#" Then
MyArray = Split(ShortString, "#")
File_Name = MyArray(UBound(MyArray))
File_Name = "d:\" & File_Name
fsstream = New System.IO.FileStream(File_Name, IO.FileMode.Create, IO.FileAccess.Write, IO.FileShare.ReadWrite)
bwwriter = New System.IO.BinaryWriter(fsstream)
bwwriter.Close()

ElseIf Microsoft.VisualBasic.Left(ShortString, 5) = "*End*" Then
fsstream = New System.IO.FileStream(File_Name, IO.FileMode.Append, IO.FileAccess.Write, IO.FileShare.ReadWrite)
bwwriter = New System.IO.BinaryWriter(fsstream)
bwwriter.Flush()
bwwriter.Close()
Else
fsstream = New System.IO.FileStream(File_Name, IO.FileMode.Append, IO.FileAccess.Write, IO.FileShare.ReadWrite)
bwwriter = New System.IO.BinaryWriter(fsstream)
bwwriter.Write(Buffer, 0, myno)
bwwriter.Flush()
bwwriter.Close()
End If
End If
Else
End If
Catch ex As Exception
MsgBox(ex.Message)
End Try
GoTo RETRY
End Sub

OK sO I decided to compare the results b/w my code and your and not so surprisingly your code is much better but with a little flaw . first let me tell you the results:

Your code: Results from Taskmanager (Performance Tab)
Program Started :0%-3% consumption (Pretty good) :)
1st Client Connects :0%-3% consumption (Really good---just what i need) :) :)
1t Client Disconnects :58% :( [Get error msg:Unable to read data from tranport connection.an existing Connection
was forcibly closed by remote Host]
I guess the huge increase in memory consumption took place because of the error. i tried to use TCPclient.client.connected method to determine if the client is still connected but as you can see i still get the error message.How can i determine if the client is not available cause if i know that then i wont call the read method...but then again your advise is needed..looking forward to hearing your response.

Oh yeah my result
Program Started :0%-3% consumption (Pretty good) :)
1st Client Connects :70% consumption (Really !!!@#) :) :)
1st Client DisConnects:70% consumption (same) :) :)
2md Client Connects :100% consumption ( youer code wins)


A candle loses nothing by lighting another candle.
Silver_Gates
@ Oleksii Prokopchuk [NCL]

I think Daves suggestion is really aproachable cause I almost have it.. but i have a problem determining whether the client is still connected or not before calling the read method. Anysuggestion what could help
A candle loses nothing by lighting another candle.
Silver_Gates

@Dave
Here when the client is connected to my server thsi code is initiated
myno = client(x).GetStream.Read(Buffer, 0,

CInt(client(x).ReceiveBufferSize)) //Blocking function I believe
Anyways so the client disconnects and we get an error message and the system resources jum way high again
resulting in the same situation as my orginal


A candle loses nothing by lighting another candle.
Silver_Gates
@DAVE I solved my problem thanks to your help

the code just needed to exit the thread....

Private Sub GetData(ByVal x As Integer)
Dim myno As Integer
Dim File_Name As String
Dim ShortString As String

Console.WriteLine("Listening For Incoming Data on " & x & " Connection")
RETRY:
Try
If client(x).Client.Connected = True Then
Dim Buffer(client(x).ReceiveBufferSize) As Byte
myno = client(x).GetStream.Read(Buffer, 0, CInt(client(x).ReceiveBufferSize))
If myno <> 0 And myno <> -1 Then
ShortString = Encoding.ASCII.GetString(Buffer, 0, myno)
'#######################################################################
'##################PROCESSING RECEIVED BUFFER IN THREAD N###############
'#######################################################################
Dim fsstream As System.IO.FileStream
Dim bwwriter As System.IO.BinaryWriter

Dim MyArray() As String
ShortString = Encoding.ASCII.GetString(Buffer, 0, myno)

If Microsoft.VisualBasic.Left(ShortString, 6) = "#Make#" Then
MyArray = Split(ShortString, "#")
File_Name = MyArray(UBound(MyArray))
File_Name = "d:\" & File_Name

fsstream = New System.IO.FileStream(File_Name, IO.FileMode.Create, IO.FileAccess.Write, IO.FileShare.ReadWrite)
bwwriter = New System.IO.BinaryWriter(fsstream)
bwwriter.Close()

ElseIf Microsoft.VisualBasic.Left(ShortString, 5) = "*End*" Then
fsstream = New System.IO.FileStream(File_Name, IO.FileMode.Append, IO.FileAccess.Write, IO.FileShare.ReadWrite)
bwwriter = New System.IO.BinaryWriter(fsstream)
bwwriter.Flush()
bwwriter.Close()
Else
fsstream = New System.IO.FileStream(File_Name, IO.FileMode.Append, IO.FileAccess.Write, IO.FileShare.ReadWrite)
bwwriter = New System.IO.BinaryWriter(fsstream)
bwwriter.Write(Buffer, 0, myno)
bwwriter.Flush()
bwwriter.Close()
End If
'##########################################################################
'###################END OF RECEIVED BUFFER PROCESSING######################
'##########################################################################

End If
Else
' MsgBox("Disconnected")
End If
Catch ex As Exception
MsgBox(ex.Message)
GoTo Finish '''''''''''''''''This part tells the thread to goto finish so that thread closes...I hate it. How can i terminate this thread from here
End Try ''''Any alternative for goto will exit sub work ??havent tested it
GoTo RETRY
finish:
End Sub


A candle loses nothing by lighting another candle.
Silver_Gates
Is it correct that you solved your problem? If so, Mark As Answerthe helpful post and Vote it As Helpful.

You can detect that client is disconnectedwhen client closes connection normally.Insome cases, the only way to determine that connection is lost is timeout when nothing is received from client. I beleive you want to detect client diconnection to free up your threads that otherwise blockedin read:you might consider startingasynchronous task that closeSocket after some time of inactivity,causing that Socket to unblock immediately and throw an exception from read.

Oleksii Prokopchuk [NCL]
Yeah My Problem is solved.. and thanks for the helpful suggestions.
the final code which is working flawlessly till now is given below...anyways if it starts bothering me again i''ll come back to you guys thanks again

Private Sub GetData(ByVal x As Integer)
Dim myno As Integer
Dim File_Name As String
Dim ShortString As String

Console.WriteLine("Listening For Incoming Data on " & x & " Connection")
While (True)
Try
If client(x).Client.Connected = True Then
Dim Buffer(client(x).ReceiveBufferSize) As Byte
myno = client(x).GetStream.Read(Buffer, 0, CInt(client(x).ReceiveBufferSize))
If myno <> 0 And myno <> -1 Then
ShortString = Encoding.ASCII.GetString(Buffer, 0, myno)
'#######################################################################
'##################PROCESSING RECEIVED BUFFER IN THREAD N###############
'#######################################################################
Dim fsstream As System.IO.FileStream
Dim bwwriter As System.IO.BinaryWriter

Dim MyArray() As String
ShortString = Encoding.ASCII.GetString(Buffer, 0, myno)

If Microsoft.VisualBasic.Left(ShortString, 6) = "#Make#" Then
MyArray = Split(ShortString, "#")
File_Name = MyArray(UBound(MyArray))
File_Name = "d:\" & File_Name

fsstream = New System.IO.FileStream(File_Name, IO.FileMode.Create, IO.FileAccess.Write, IO.FileShare.ReadWrite)
bwwriter = New System.IO.BinaryWriter(fsstream)
bwwriter.Close()

ElseIf Microsoft.VisualBasic.Left(ShortString, 5) = "*End*" Then
fsstream = New System.IO.FileStream(File_Name, IO.FileMode.Append, IO.FileAccess.Write, IO.FileShare.ReadWrite)
bwwriter = New System.IO.BinaryWriter(fsstream)
bwwriter.Flush()
bwwriter.Close()
Else
fsstream = New System.IO.FileStream(File_Name, IO.FileMode.Append, IO.FileAccess.Write, IO.FileShare.ReadWrite)
bwwriter = New System.IO.BinaryWriter(fsstream)
bwwriter.Write(Buffer, 0, myno)
bwwriter.Flush()
bwwriter.Close()
End If
'##########################################################################
'###################END OF RECEIVED BUFFER PROCESSING#############################
'##########################################################################

End If
Else
Console.WriteLine("Client Has Been Disconnected")
End If
Catch ex As Exception
If Err.Number = 57 Then 'Client Disconnected
Console.WriteLine("Client Diconnected")
Exit While
Else
MsgBox(Err.Description)
MsgBox(Err.Number)
End If

End Try
End While
End Sub

If you find any drawbacks here do let me know... Thanks Again

A candle loses nothing by lighting another candle.
Silver_Gates

You can use google to search for other answers

Custom Search

More Threads

• how SocketEventAsyncArgs works
• Rate limitation on reception of UDP messages
• help!!!
• FTP in .NET, get list of only subfolders or only files
• Anomolous blocking behavior in TcpClient
• TcpClient: what happens when server thread killed by another process?
• HTTP authentication
• HTTP Get interface to get .gif file or xml file
• DynDns like software
• HTTP protocol errors when combining WebClient uploads and digest authentication