Connecting Tech Pros Worldwide Forums | Help | Site Map

HTTP Webserver - tcp thread issues

Microsoft News
Guest
 
Posts: n/a
#1: Nov 15 '05
Hi,

I have been using several http server code examples from the web, include
one from msdn, and I can't seem to get a simple http server thread working.
I can connect the server successful using IE6 and following url:
http://127.0.0.1:5050
But when I attempt a second connect the windows symbol in the upper right
corner of ie starts in motion and nothing happens it just sits there waiting
for a response. The code also behaves very strangely when I try to debug
it, it will jump out of the serverThread function in the middle of the
stream.read loop and not return any exceptions, I'm really lost on this one.
The code also really seems to stumble when I use IE's refresh button rather
than typing in the URL if you can believe it.

I have included the class in question below stripped to the bone. Any
feedback would be appreciated.

-----

using System;

using System.Net;

using System.Net.Sockets;

using System.Text;

using System.Threading;

namespace httpserv

{

/// <summary>

/// Summary description for PeerNetServer.

/// </summary>

public class httpserv

{

TcpListener listener;

private int port = 5050;

private Thread serverThread;

public httpserv()

{

//

// TODO: Add constructor logic here

//

}

public void Start()

{

listener = new TcpListener(IPAddress.Parse("127.0.0.1"), port);

serverThread = new Thread(new ThreadStart(ServerThread));

listener.Start();

serverThread.Start();

}

public void Stop()

{

listener.Stop();

serverThread.Abort();

}

private void ServerThread()

{

while(true)

{

TcpClient client = listener.AcceptTcpClient();

NetworkStream stream = client.GetStream();

int bytesRead;

Byte[] buffer = new Byte[1024];

string request = "";

while((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0)

{

request = request + Encoding.ASCII.GetString(buffer, 0, bytesRead);

}

string output = "HTTP/1.1 200 OK\r\n";

output = output + "Content-type: text/plain\r\n";

output = output + "Content-length: " + request.Length + "\r\n";

output = output + "\r\n";

output = output + request;

byte[] msg = System.Text.Encoding.ASCII.GetBytes(output);

stream.Write(msg, 0, msg.Length);

//stream.Flush(); // Documentation claims it doesn't do anything at this
time but thought I'd try it anyway

client.Close();

}

}

}

}



-----

Thanks in advance,
Dave



Joerg Jooss
Guest
 
Posts: n/a
#2: Nov 15 '05

re: HTTP Webserver - tcp thread issues


Dave wrote:
[color=blue]
> Hi,
>
> I have been using several http server code examples from the web,
> include one from msdn, and I can't seem to get a simple http server
> thread working. I can connect the server successful using IE6 and
> following url: http://127.0.0.1:5050
> But when I attempt a second connect the windows symbol in the upper
> right corner of ie starts in motion and nothing happens it just sits
> there waiting for a response. The code also behaves very strangely
> when I try to debug it, it will jump out of the serverThread
> function in the middle of the stream.read loop and not return any
> exceptions, I'm really lost on this one. The code also really seems
> to stumble when I use IE's refresh button rather than typing in the
> URL if you can believe it.
>
> I have included the class in question below stripped to the bone.
> Any feedback would be appreciated.[/color]
[...]

That's a singlethreaded implementation -- the main server thread should
spawn a new thread for each request accepted. Check out the Cassini web
server at www.asp.net.

Cheers,
--
Joerg Jooss
joerg.jooss@gmx.net
Microsoft News
Guest
 
Posts: n/a
#3: Nov 15 '05

re: HTTP Webserver - tcp thread issues


Thanks Joerg,

Cassini looks like it will be very helpful, it is definitely a more complete
package than any of the examples I have come across to date, but I'd still
like to understand why my simple example doesn't work as expected before
getting into more complex examples. Even though it is single threaded
shouldn't the listener make itself available again once it has finished
processing a request? I'd also like to try to understand why it is not
consistently serving up the first request.

Thanks,
Dave

"Joerg Jooss" <joerg.jooss@gmx.net> wrote in message
news:uyH7WKrzDHA.536@tk2msftngp13.phx.gbl...[color=blue]
> Dave wrote:
>[color=green]
> > Hi,
> >
> > I have been using several http server code examples from the web,
> > include one from msdn, and I can't seem to get a simple http server
> > thread working. I can connect the server successful using IE6 and
> > following url: http://127.0.0.1:5050
> > But when I attempt a second connect the windows symbol in the upper
> > right corner of ie starts in motion and nothing happens it just sits
> > there waiting for a response. The code also behaves very strangely
> > when I try to debug it, it will jump out of the serverThread
> > function in the middle of the stream.read loop and not return any
> > exceptions, I'm really lost on this one. The code also really seems
> > to stumble when I use IE's refresh button rather than typing in the
> > URL if you can believe it.
> >
> > I have included the class in question below stripped to the bone.
> > Any feedback would be appreciated.[/color]
> [...]
>
> That's a singlethreaded implementation -- the main server thread should
> spawn a new thread for each request accepted. Check out the Cassini web
> server at www.asp.net.
>
> Cheers,
> --
> Joerg Jooss
> joerg.jooss@gmx.net[/color]


Joerg Jooss
Guest
 
Posts: n/a
#4: Nov 15 '05

re: HTTP Webserver - tcp thread issues


News" <nospam> wrote:
[color=blue]
> Thanks Joerg,
>
> Cassini looks like it will be very helpful, it is definitely a more
> complete package than any of the examples I have come across to
> date, but I'd still like to understand why my simple example doesn't
> work as expected before getting into more complex examples. Even
> though it is single threaded shouldn't the listener make itself
> available again once it has finished processing a request? I'd also
> like to try to understand why it is not consistently serving up the
> first request.[/color]

Well, it should. After looking at your code again, there are still a
couple of issues that need to be taken care of:

1. Utter lack of exception handling ;-) This is quite dangerous anyway,
but since 99.9% of all exceptions are to be expected in the main server
thread, a simple try/catch in main() won't help.

2. Review the docs for TcpClient and NetworkStream on MSDN. For example:
"You must close the NetworkStream when you are through sending and
receiving data. Closing TcpClient does not release the NetworkStream."

Unfortunately, MSDN's own samples are sometimes wrong if this is true. I
guess not adhering to those guidelines may have weird side effects.

3. If you know Java (or better its java.net package), a multithreaded
HTTP server can be found at
http://www.devhood.com/tutorials/tut...utorial_id=396
&printer=t

ServerSocket becomes TcpListener, and accept() becomes either
AcceptSocket() or AcceptTcpClient() etc.

Cheers,
--
Joerg Jooss
joerg.jooss@gmx.net
Dave
Guest
 
Posts: n/a
#5: Nov 15 '05

re: HTTP Webserver - tcp thread issues


Thanks for the tips. Believe it or not removing the read loop and replacing
it with a single read command helped correct the problem. I still haven't
figured out why but I'll keep playing with it until it hits me.

Once the first request was working closing the socket, as you suggested,
made a huge difference in performance. I'm surprised it was not in any of
the online examples I looked at.

As far as exception handling goes - I know it is less than optimal :). I
removed any code that was not necessary for the server to run, once I
determine that exceptions were not being thrown when my code was
misbehaving, in order to make pin pointing the problem a little easier, but
don't worry, I will be sure to add plenty of exception handling once I am
happy with the basic functionality.

Thanks Again,
Dave

"Joerg Jooss" <joerg.jooss@gmx.net> wrote in message
news:eHB0hC4zDHA.484@TK2MSFTNGP10.phx.gbl...[color=blue]
> News" <nospam> wrote:
>[color=green]
> > Thanks Joerg,
> >
> > Cassini looks like it will be very helpful, it is definitely a more
> > complete package than any of the examples I have come across to
> > date, but I'd still like to understand why my simple example doesn't
> > work as expected before getting into more complex examples. Even
> > though it is single threaded shouldn't the listener make itself
> > available again once it has finished processing a request? I'd also
> > like to try to understand why it is not consistently serving up the
> > first request.[/color]
>
> Well, it should. After looking at your code again, there are still a
> couple of issues that need to be taken care of:
>
> 1. Utter lack of exception handling ;-) This is quite dangerous anyway,
> but since 99.9% of all exceptions are to be expected in the main server
> thread, a simple try/catch in main() won't help.
>
> 2. Review the docs for TcpClient and NetworkStream on MSDN. For example:
> "You must close the NetworkStream when you are through sending and
> receiving data. Closing TcpClient does not release the NetworkStream."
>
> Unfortunately, MSDN's own samples are sometimes wrong if this is true. I
> guess not adhering to those guidelines may have weird side effects.
>
> 3. If you know Java (or better its java.net package), a multithreaded
> HTTP server can be found at
> http://www.devhood.com/tutorials/tut...utorial_id=396
> &printer=t
>
> ServerSocket becomes TcpListener, and accept() becomes either
> AcceptSocket() or AcceptTcpClient() etc.
>
> Cheers,
> --
> Joerg Jooss
> joerg.jooss@gmx.net[/color]


Mike Junkin
Guest
 
Posts: n/a
#6: Nov 15 '05

re: HTTP Webserver - tcp thread issues


Dave,

There's a couple problems. First your reading until you get a zero
byte return. That will only happen when the socket is closed by the
client. The client won't close the socket because it's waiting for
your response.

You need to read until you get to the end of the HTTP request. So
read and append to a buffer. Then check the buffer end for
'\r\n\r\n'.

Second is IE is using HTTP 1.1 with keep alives. So it's going to
keep reading until either you close the socket or send the correct
HTTP 1.1 response. Frankly I'm not sure what that is - been a while
since I read the HTTP spec.

Easy thing to do is simply close the socket. Which is not happening
with your code because you've got an un-disposed network stream
that's holding the socket open.


Here's your ServiceThread function modified to do what I think your
after:

private void ServerThread()
{
int requestCounter = 0;

Byte[] buffer = new Byte[1024];
char[] charBuf = new char[1024];
StringBuilder sb = new StringBuilder(1024,4096);

while(true)
{
using( TcpClient client = _listener.AcceptTcpClient())
{
using( NetworkStream stream = client.GetStream())
{
++requestCounter;

int bytesRead;
int charsConverted;

while((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0)
{
charsConverted =
Encoding.ASCII.GetChars(buffer,0,bytesRead,charBuf ,0);

if(charsConverted > 0)
{
sb.Append(charBuf,0,charsConverted);

int currentRequestSize = sb.Length;

if(currentRequestSize > 3)
{
if('\n' == sb[currentRequestSize-1] && '\r' ==
sb[currentRequestSize-2] &&
'\n' == sb[currentRequestSize-3] && '\r' ==
sb[currentRequestSize-4])
{
// we've got our request
break;
}
}
// else we don't have a full HTTP request yet so keep reading
}
else
{
// if we don't throw here we risk missing the \r\n and hanging
for more input

throw new ApplicationException("failed to convert HTTP request
to ascii characters");
}
}

string request = "request [" + requestCounter.ToString() + "] " +
sb.ToString();

sb.Remove(0,sb.Length);

string output = "HTTP/1.1 200 OK\r\n";
output = output + "Content-type: text/plain\r\n";
output = output + "Content-length: " + request.Length + "\r\n";
output = output + "\r\n";
output = output + request;

byte[] msg = System.Text.Encoding.ASCII.GetBytes(output);

stream.Write(msg, 0, msg.Length);

} // using stream
} // using client
} // forever
} // end ServerThread

[color=blue]
> Davewrote:[/color]
Thanks for the tips. Believe it or not removing the read loop and
replacing[color=blue]
> it with a single read command helped correct the problem. I still[/color]
haven't[color=blue]
> figured out why but I'll keep playing with it until it hits me.
>
> Once the first request was working closing the socket, as you[/color]
suggested,[color=blue]
> made a huge difference in performance. I'm surprised it was not in[/color]
any of[color=blue]
> the online examples I looked at.
>
> As far as exception handling goes - I know it is less than optimal[/color]
:). I[color=blue]
> removed any code that was not necessary for the server to run, once[/color]
I[color=blue]
> determine that exceptions were not being thrown when my code was
> misbehaving, in order to make pin pointing the problem a little[/color]
easier, but[color=blue]
> don't worry, I will be sure to add plenty of exception handling once[/color]
I am[color=blue]
> happy with the basic functionality.
>
> Thanks Again,
> Dave
>
> "Joerg Jooss" <joerg.jooss@gmx.net> wrote in message
> news:eHB0hC4zDHA.484@TK2MSFTNGP10.phx.gbl...
> News" <nospam> wrote:
>
> Thanks Joerg,
>
> Cassini looks like it will be very helpful, it is definitely a more
> complete package than any of the examples I have come across to
> date, but I'd still like to understand why my simple example[/color]
doesn't[color=blue]
> work as expected before getting into more complex examples. Even
> though it is single threaded shouldn't the listener make itself
> available again once it has finished processing a request? I'd[/color]
also[color=blue]
> like to try to understand why it is not consistently serving up the
> first request.
>
> Well, it should. After looking at your code again, there are still[/color]
a[color=blue]
> couple of issues that need to be taken care of:
>
> 1. Utter lack of exception handling ;-) This is quite dangerous[/color]
anyway,[color=blue]
> but since 99.9% of all exceptions are to be expected in the main[/color]
server[color=blue]
> thread, a simple try/catch in main() won't help.
>
> 2. Review the docs for TcpClient and NetworkStream on MSDN. For[/color]
example:[color=blue]
> "You must close the NetworkStream when you are through sending and
> receiving data. Closing TcpClient does not release the[/color]
NetworkStream."[color=blue]
>
> Unfortunately, MSDN's own samples are sometimes wrong if this is[/color]
true. I[color=blue]
> guess not adhering to those guidelines may have weird side effects.
>
> 3. If you know Java (or better its java.net package), a[/color]
multithreaded[color=blue]
> HTTP server can be found at
>[/color]
http://www.devhood.com/tutorials/tut...utorial_id=396[color=blue]
> &printer=t
>
> ServerSocket becomes TcpListener, and accept() becomes either
> AcceptSocket() or AcceptTcpClient() etc.
>
> Cheers,
> --
> Joerg Jooss
> joerg.jooss@gmx.net[/quote][/color]



----== Posted via Newsfeed.Com - Unlimited-Uncensored-Secure Usenet News==----
http://www.newsfeed.com The #1 Newsgroup Service in the World! >100,000 Newsgroups
---= 19 East/West-Coast Specialized Servers - Total Privacy via Encryption =---
Dave
Guest
 
Posts: n/a
#7: Nov 15 '05

re: HTTP Webserver - tcp thread issues


Thanks for the help Mike. I've found that closing the socket helped quit a
bit, obvious I should spend a little time with the http 1.1 spec. Your
explanation of the read issue also makes things a little clearer. My
solution to this point was to open a second stream for writing after the
read stream closed, which is obviously not the most efficient way to handle
this situation. I appreciate you taking the time to include a code example
as well, it has been most helpful.

Thanks Again,
Dave


"Mike Junkin" <mikejunkin@hotmail-dot-com.no-spam.invalid> wrote in message
news:3ff37acf$1_2@127.0.0.1...[color=blue]
> Dave,
>
> There's a couple problems. First your reading until you get a zero
> byte return. That will only happen when the socket is closed by the
> client. The client won't close the socket because it's waiting for
> your response.
>
> You need to read until you get to the end of the HTTP request. So
> read and append to a buffer. Then check the buffer end for
> '\r\n\r\n'.
>
> Second is IE is using HTTP 1.1 with keep alives. So it's going to
> keep reading until either you close the socket or send the correct
> HTTP 1.1 response. Frankly I'm not sure what that is - been a while
> since I read the HTTP spec.
>
> Easy thing to do is simply close the socket. Which is not happening
> with your code because you've got an un-disposed network stream
> that's holding the socket open.
>
>
> Here's your ServiceThread function modified to do what I think your
> after:
>
> private void ServerThread()
> {
> int requestCounter = 0;
>
> Byte[] buffer = new Byte[1024];
> char[] charBuf = new char[1024];
> StringBuilder sb = new StringBuilder(1024,4096);
>
> while(true)
> {
> using( TcpClient client = _listener.AcceptTcpClient())
> {
> using( NetworkStream stream = client.GetStream())
> {
> ++requestCounter;
>
> int bytesRead;
> int charsConverted;
>
> while((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0)
> {
> charsConverted =
> Encoding.ASCII.GetChars(buffer,0,bytesRead,charBuf ,0);
>
> if(charsConverted > 0)
> {
> sb.Append(charBuf,0,charsConverted);
>
> int currentRequestSize = sb.Length;
>
> if(currentRequestSize > 3)
> {
> if('\n' == sb[currentRequestSize-1] && '\r' ==
> sb[currentRequestSize-2] &&
> '\n' == sb[currentRequestSize-3] && '\r' ==
> sb[currentRequestSize-4])
> {
> // we've got our request
> break;
> }
> }
> // else we don't have a full HTTP request yet so keep reading
> }
> else
> {
> // if we don't throw here we risk missing the \r\n and hanging
> for more input
>
> throw new ApplicationException("failed to convert HTTP request
> to ascii characters");
> }
> }
>
> string request = "request [" + requestCounter.ToString() + "] " +
> sb.ToString();
>
> sb.Remove(0,sb.Length);
>
> string output = "HTTP/1.1 200 OK\r\n";
> output = output + "Content-type: text/plain\r\n";
> output = output + "Content-length: " + request.Length + "\r\n";
> output = output + "\r\n";
> output = output + request;
>
> byte[] msg = System.Text.Encoding.ASCII.GetBytes(output);
>
> stream.Write(msg, 0, msg.Length);
>
> } // using stream
> } // using client
> } // forever
> } // end ServerThread
>
>[color=green]
> > Davewrote:[/color]
> Thanks for the tips. Believe it or not removing the read loop and
> replacing[color=green]
> > it with a single read command helped correct the problem. I still[/color]
> haven't[color=green]
> > figured out why but I'll keep playing with it until it hits me.
> >
> > Once the first request was working closing the socket, as you[/color]
> suggested,[color=green]
> > made a huge difference in performance. I'm surprised it was not in[/color]
> any of[color=green]
> > the online examples I looked at.
> >
> > As far as exception handling goes - I know it is less than optimal[/color]
> :). I[color=green]
> > removed any code that was not necessary for the server to run, once[/color]
> I[color=green]
> > determine that exceptions were not being thrown when my code was
> > misbehaving, in order to make pin pointing the problem a little[/color]
> easier, but[color=green]
> > don't worry, I will be sure to add plenty of exception handling once[/color]
> I am[color=green]
> > happy with the basic functionality.
> >
> > Thanks Again,
> > Dave
> >
> > "Joerg Jooss" <joerg.jooss@gmx.net> wrote in message
> > news:eHB0hC4zDHA.484@TK2MSFTNGP10.phx.gbl...
> > News" <nospam> wrote:
> >
> > Thanks Joerg,
> >
> > Cassini looks like it will be very helpful, it is definitely a more
> > complete package than any of the examples I have come across to
> > date, but I'd still like to understand why my simple example[/color]
> doesn't[color=green]
> > work as expected before getting into more complex examples. Even
> > though it is single threaded shouldn't the listener make itself
> > available again once it has finished processing a request? I'd[/color]
> also[color=green]
> > like to try to understand why it is not consistently serving up the
> > first request.
> >
> > Well, it should. After looking at your code again, there are still[/color]
> a[color=green]
> > couple of issues that need to be taken care of:
> >
> > 1. Utter lack of exception handling ;-) This is quite dangerous[/color]
> anyway,[color=green]
> > but since 99.9% of all exceptions are to be expected in the main[/color]
> server[color=green]
> > thread, a simple try/catch in main() won't help.
> >
> > 2. Review the docs for TcpClient and NetworkStream on MSDN. For[/color]
> example:[color=green]
> > "You must close the NetworkStream when you are through sending and
> > receiving data. Closing TcpClient does not release the[/color]
> NetworkStream."[color=green]
> >
> > Unfortunately, MSDN's own samples are sometimes wrong if this is[/color]
> true. I[color=green]
> > guess not adhering to those guidelines may have weird side effects.
> >
> > 3. If you know Java (or better its java.net package), a[/color]
> multithreaded[color=green]
> > HTTP server can be found at
> >[/color]
> http://www.devhood.com/tutorials/tut...utorial_id=396[color=green]
> > &printer=t
> >
> > ServerSocket becomes TcpListener, and accept() becomes either
> > AcceptSocket() or AcceptTcpClient() etc.
> >
> > Cheers,
> > --
> > Joerg Jooss
> > joerg.jooss@gmx.net[/quote][/color]
>
>
>
> ----== Posted via Newsfeed.Com - Unlimited-Uncensored-Secure Usenet[/color]
News==----[color=blue]
> http://www.newsfeed.com The #1 Newsgroup Service in the World! >100,000[/color]
Newsgroups[color=blue]
> ---= 19 East/West-Coast Specialized Servers - Total Privacy via Encryption[/color]
=---


Closed Thread