Does HttpListener have the same quirk as HttpWebRequest

  • Thread starter Thread starter Mark
  • Start date Start date
M

Mark

Hi...

We've implemented a server process using HttpListener to get and process
certain requests, but we've been noticing some odd serialization that
reminded me of a quirk in the client code.

We recently discovered an odd behavior of HttpWebRequest in the client code
where mixing sync and async methods resulted in everything quietly being
sync. Specifically, we were using GetRequestStream() to send the data up
synchronously then calling BeginGetResponse() to wait for the answer async.
Well, it turned out that if you call a sync method first the async calls
magically turn into synchronized ones - a rather undocumented behavior.

Now we're seeing some similar quirks on the server side with HttpListener.
We use BeginGetContext() to listen for a request. Our callback calls
EndGetContext() to get the details and then immediately calls
BeginGetContext() again to wait for another request.

But then we read the request synchronously, post the work in a queue with
the associated response object and move on.

What we're seeing is that if the client sends several requests in a row, it
blasts right through them but the server doesn't acknowledge even reading the
2nd request until after the response to the first request is written to and
closed.

Does HttpListener have some implicit serialization behavior like
HttpWebRequest?

Thanks
Mark
 
Hi Mark,

From your description here, you've encountered some similar blocking
problem when using both sync and async processing with HttpListener class?
So far I can not give you a definte answer on this since I haven't got such
async processing related issue about the HttpListener class. I think to get
the actual implementation of this class and how to works, it will require
contacting some of the dev engineers. Would you simplify the problem
context and make a brief description of the issue you encountered and the
questions you wonder, I can try helping you look for some dev specific
engineers to query some further information on this.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we

can improve the support we provide to you. Please feel free to let my
manager know what you think of

the level of service provided. You can send feedback directly to my manager
at: (e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to

http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response

from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take

approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution.

The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump

analysis issues. Issues of this nature are best handled working with a
dedicated Microsoft Support

Engineer by contacting Microsoft Customer Support Services (CSS) at

http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.

--------------------
From: =?Utf-8?B?TWFyaw==?= <[email protected]>
Subject: Does HttpListener have the same quirk as HttpWebRequest
Date: Thu, 6 Mar 2008 15:05:02 -0800
Lines: 32
 
Hi Steven...

I've been trying to boil things down to a smaller, reproducible case which
is taking some time. I'm also running into things that don't seem entirely
clear to me in the documentation; hopefully you can offer some clarification.

On the client side, I'm using
HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://127.0.0.1/");
req.ConnectionGroupName = "1";
req.KeepAlive = true;
req.AllowAutoRedirect = false;
req.Method = "POST";
req.ContentLength = this.bytes.Length;
req.Proxy = null;

to try and pipeline a group of requests on a single connection. By looking
at the request headers, the response headers and certain other properties, I
see that both are agreeing to HTTP/1.1 and the client is sending Connection:
Keep-Alive. The server HttpListener responses only have Content-Length,
Date, and Server headers in the response.

But when I look at the HttpRequest.ServicePoint.CurrentConnections I see a
number > 1 and equal to the number of concurrent requests I have outstanding.
When I look at HttpRequest.ServicePoint.SupportsPipelining it's true.

So is the HttpRequest.ServicePoint.CurrentConnections number reflecting the
number of actual sockets that ServicePoint is managing or the number of
requests it has pipelined?

Also, the MSDN doc page for ServicePoint.CurrentConnections has the wrong
sample code on it; the code samples are for ServicePoint.Address.

Thanks
Mark
 
Hi Steven...

I'm still working on trying to get a smaller reproducible case, but I've
also tried to get some other statistics. I'm getting the impression that
both the ServicePoint on the client side and the HttpListener on the server
side are going to some lengths to obscure how many actual sockets you have
and how many requests are pipelined.

I'm thinking the one that's having problems is having it with some pipelining.

On the client side, I added statistics to show the time between
BeginGetRequestStream() and the requestStream.close() in the completion
routine - the time to get a connection and write the bytes up. Every now and
again, I see jumps of about 45 milliseconds; I'm guessing that the 45 ms is
the time to spin up a new socket to make a request.

As long as the client waits for a response to the question before sending
another request, the next request seems to re-use the same socket (transfer
time is 0 ms).

On one occasion, though, when the client fired 2 requests at once, it looks
like another socket is fired up for the 2nd request (it has the 45 ms lag).

My problem, though, is that it gets in a state again where the client sends
2 requests at once but the ServicePoint *doesn't* spin up a new socket.
Instead it waits until the first request is finished to pipeline the next
request and doesn't send the data until the first one clears.

So my question is slightly clarified to "How does one determine when a
request will be pipelined vs having a separate socket created?"

The packets are all about the same size and for the most part the protocol
being implemented (xmpp 0124) is call/response, but there are occasions where
some calls don't require an answer and some out-of-band data comes from the
server, piggy-backed in other requests. The extra out-of-band responses from
the server may spawn more concurrent requests.

Thanks
Mark
 
Thanks for your followup Mark,

Yes, if we can make the problem scenario simplified that will be much
helpful. Also, I've tried forwarding this question to some other dev
engineers related to the network component classes. However, since the
problem context maybe a bit complex to explain and the problem here also
include some context from a former thread(about httpwebrequest), I'm not
sure whether they'll 100% get the things we're investigating here. Anyway,
I'll inform you of any update I get from them.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we

can improve the support we provide to you. Please feel free to let my
manager know what you think of

the level of service provided. You can send feedback directly to my manager
at: (e-mail address removed).
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.

--------------------
From: =?Utf-8?B?TWFyaw==?= <[email protected]>
References: <[email protected]>
 
Hi Mark,

Just got some info from the dev engineer. He told me that for the question
on "the number of actual sockets that ServicePoint is managing", in this
case, the client requests can't be pipelined because they use the POST verb
which is not idempotent (http://tools.ietf.org/rfc/rfc2616.txt "8.1.2.2
Pipelining").

Regards,

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

This posting is provided "AS IS" with no warranties, and confers no rights.

--------------------
 
Hi Steven,

Thank you for persisting in this question, and I'm sorry I didn't check back
sooner to see your response.

"Steven Cheng" said:
Just got some info from the dev engineer. He told me that for the question
on "the number of actual sockets that ServicePoint is managing", in this
case, the client requests can't be pipelined because they use the POST verb
which is not idempotent (http://tools.ietf.org/rfc/rfc2616.txt "8.1.2.2
Pipelining").

I read the relevant sections of the spec, and it seems to me they haven't
been very accurate in a long time. Once server-side scripting and cookies
go added, GET requests are no longer idempotent (i.e. the response from N > 0
of the same requests can and often will be different). There's also no
mention that POST could be idempotent with the stipulation that the same
payload was sent on each of the multiple requests.

That aside, I still come back to the actual behavior of the ServicePoint.

I think I just figured it out going back and forth in the docs.
ServicePoint.ConnectionLimit comes from
ServicePointManager.DefaultConnectionLimit which is 2 unless the app
configures some other value.

What I think is happening is that when my client sends multiple concurrent
requests, the first one goes over the pooled socket. The 2nd one spins up
another socket. The 3rd request hits the ConnectionLimit, so it has to be
queued behind someone.

I'm guessing here but it seems like the 3rd request gets onto a queue tied
to a specific socket, so it can only be sent when the last request completes.
In my case, it ends up getting queued behind socket #1 (which takes 5
seconds to complete) even though socket #2 completes much sooner and could
have been used.

Could you ask if a new request to a ServicePoint after
ServicePoint.ConnectionLimit is reached gets queued with a particular
connection and not the ServicePoint in general?

Thanks
Mark
 
Back
Top