Reputation: 825
I'm trying to display on the screen any data that comes from the ssl stream (From a website). Since I don't know when the data are going to arrive, I used another thread which keeps reading from the stream until bytes have been read. This works perfectly, however, my CPU usages jumps to 25% and stays there (That's 1 thread at maximum usage, my PC has 4 threads). Although this does kinda make sense since the thread is stuck in a while loop, I wasn't expecting an instance of the Thread class to consume a whole thread of my CPU (I could swear this wasn't happening when using a simple Client/Server application).
The thread starts running as soon as the connection is initialized, the user can send data to the website any time he wants and the application is supposed to print out the response. What would be an alternative solutions to this? Should I drop SslStream and start using something else?
Here's the code that runs on this separate thread:
void ReadDataAsync(Object obj) {
byte[] buffer = new byte[65536]; //65536, make sure all bytes can be
//from a single packet
int bytesRead = -1;
while (true) {
//It makes sense for sslStream.Read to block until bytes have been
//read, but it doesn't. Which is why I'm checking if bytesRead!=0
bytesRead = sslStream.Read(buffer, 0, 65536);
if (bytesRead != 0) {
Console.WriteLine(Encoding.UTF8.GetString(buffer, 0, bytesRead));
buffer = new byte[65536];
}
}
}
Thank you everyone, I appreciate your help
Edit:
I tried using BeginRead and EndRead instead, as "gt" suggested. For this, I'm using BeginRead whenever a request is being sent by the user. When all the data have been received I print them on the screen. This seems to work fine but I'm concerned about whether there will be any problems in the future. Is there any chance that the packets get messed up? For example, is it possible that EndRead doesn't return 0 at the end of the first packet and it keeps on reading the second packet? If that's possible, how would I go on solving this? The data received is just the body of the http layer, so I can't access the IP layer beforehand to know the length of the packet.
public void SendData(byte[] message) {
sslStream.Write(message);
sslStream.Flush();
//Start reading for response (if not already reading)
if (sslStream.CanRead) {
sslStream.BeginRead(buffer, 0, BufferSize, ReadData, null);
}
}
void ReadData(IAsyncResult ar) {
int bytesRead = sslStream.EndRead(ar);
if (bytesRead > 0) {
//data may be on their way so start reading again
message.Append(Encoding.UTF8.GetString(buffer, 0, bytesRead));
sslStream.BeginRead(buffer, 0, BufferSize, ReadData, null);
Console.WriteLine("Data received but more may be on their way...");
} else {
//All data arrived (Checking if length is more than 0 since all the
//data may had already arrived in the previous check (above)
if (message.ToString().Length > 0) {
Console.WriteLine(message.ToString());
//Clear StringBuilder and reset buffer.
message.Clear();
buffer = new byte[BufferSize];
}
}
}
Thanks again
Upvotes: 1
Views: 1870
Reputation: 7463
Seeing while(true)
is usually a bad sign... If your code enters a 'tight' loop without an end condition, it will keep looping and consume all the available resources to it.
Double-check that the 'if' condition is doing what you expect it to. For example, what happens if the stream is read in more than one part? (e.g. two parts of 32768). This is entirely possible.
Once you are happy with the behaviour, you could force the thread to sleep for a bit before trying the next Read
, using Thread.Sleep(100)
.
Alternatively, try looking into asynchronous IO, using BeginRead
. See this example on MSDN.
Edit, to answer part 2 of the question:
I suspect that if something can go wrong, it will go wrong, so code defensively! A solution to the next problem, is to buffer all data read from the stream. Then have another thread attempt to read whole packets from the buffer. Don't forget to use locks to prevent the buffer from being read/written to at the same time.
It would also be a good idea to write unit tests for this, to cover the 'fragmented' behaviour (as well as the normal behaviour).
Alternatively, you might be able to look into a higher level protocol which takes care of these things for you. One I often see mentioned is Google's Protocol Buffers.
Upvotes: 1