简体   繁体   English

.Net HttpListener.GetContext()为客户端提供“503 Service Unavailable”

[英].Net HttpListener.GetContext() gives “503 Service Unavailable” to the client

I am trying to write a very very simple custom Http server in C#. 我想在C#中编写一个非常简单的自定义Http服务器。

The code to achieve a connection is as simple as .Net offers it: 实现连接的代码就像.Net提供的那样简单:

 // get our IPv4 address
 IPAddress[] localIPs = Dns.GetHostAddresses(Dns.GetHostName());
 IPAddress theAddress = localIPs.Where(ip => ip.AddressFamily == AddressFamily.InterNetwork).FirstOrDefault();

 // Create a http listener.
 var listener = new HttpListener();
 string myUrlPrefix = $"http://{theAddress.ToString()}:{port}/MyService/";
 listener.Prefixes.Add(myUrlPrefix);
 Console.WriteLine($"Trying to listen on {myUrlPrefix}");
 listener.Start();
 Console.WriteLine("Listening...");
 HttpListenerContext context = null;
 try
 {
     context = listener.GetContext();
 }
 catch(Exception ex)
 {
     Console.WriteLine(ex.Message);
 }

 HttpListenerRequest request = context.Request;

When running this, GetContext() blocks, never returns and does not throw an exception. 运行它时, GetContext()阻塞,永远不会返回并且不会抛出异常。

listener.Start() works -- the URL is properly reserved for the correct user with 'netsh http add urlacl...'., else Start() would throw. The URL is also only reserved once listener.Start() works -- the URL is properly reserved for the correct user with 'netsh http add urlacl...'., else Start() would throw. The URL is also only reserved once . listener.Start() works -- the URL is properly reserved for the correct user with 'netsh http add urlacl...'., else Start() would throw. The URL is also only reserved once

I can see with netstat -na that the port is being listened on. 我可以看到netstat -na正在监听端口。

I am trying to access this with either a browser or with the cygwin implementation of wget . 我试图通过浏览器或wgetcygwin实现来访问它。 Both give me "ERROR 503: Service Unavailable." 两者都给我"ERROR 503: Service Unavailable." .

Here is the wget output: 这是wget输出:

$ wget http://127.0.0.1:45987/MyService/
--2016-03-06 14:54:37--  http://127.0.0.1:45987/MyService/
Connecting to 127.0.0.1:45987... connected.
HTTP request sent, awaiting response... 503 Service Unavailable
2016-03-06 14:54:37 ERROR 503: Service Unavailable.

This means that the TCP connection gets established, yet HttpListener.GetContext() does not bother to service the request and give me the context, it also doesn't bother to at least throw an exception to tell me what's wrong. 这意味着TCP连接已建立,但HttpListener.GetContext()并不打算为请求提供服务并给我上下文,它也至少不会抛出异常来告诉我什么是错误的。 It just closes the connection. 它只是关闭连接。 From the debug output, it doesn't even have a First-Chance exception inside that it would catch itself. 从调试输出来看,它内部甚至没有First-Chance异常。

I have searched the Net and Stackoverflow up and down and don't find anything useful. 我上下搜索了Net和Stackoverflow,但没有找到任何有用的东西。

There are no errors in the Windows Event log. Windows事件日志中没有错误。

This is Windows 10 Pro and Microsoft Visual Studio Community 2015 Version 14.0.23107.0 D14REL with Microsoft .NET Framework Version 4.6.01038. 这是Windows 10 Pro和Microsoft Visual Studio社区2015版本14.0.23107.0 D14REL与Microsoft .NET Framework版本4.6.01038。

It may be worth mentioning that I have also tested this with all firewalls off, still the same result. 值得一提的是,我还测试了所有防火墙关闭,仍然是相同的结果。

Does anyone have any idea what could be going wrong in the GetContext() and how I could debug or solve this? 有没有人知道GetContext()可能出现什么问题以及我如何调试或解决这个问题?

====== ======

EDIT: I have enabled .Net Framework source stepping and have stepped into GetContext(). 编辑:我已启用.Net Framework源步进并已进入GetContext()。 The blocking and refusal to service http requests happens in something called "UnsafeNclNativeMethods.HttpApi.HttpReceiveHttpRequest" which, I guess, might be the native HttpReceiveHttpRequest method documented at https://msdn.microsoft.com/en-us/library/windows/desktop/aa364495(v=vs.85).aspx . 阻止和拒绝服务http请求发生在名为“UnsafeNclNativeMethods.HttpApi.HttpReceiveHttpRequest”的内容中,我想这可能是https://msdn.microsoft.com/en-us/library/windows/中记录的本机HttpReceiveHttpRequest方法。 desktop / aa364495(v = vs.85).aspx So it's the native API that is refusing my request. 所以它是拒绝我的请求的本机API。

I haven't found a solution, but a workaround. 我还没有找到解决方案,而是一种解决方法。

Interestingly, if I go a level deeper and use a plain TcpListener, I have no problem receiving the request as plain text. 有趣的是,如果我更深层次并使用普通的TcpListener,我可以毫无疑问地接收纯文本请求。

 // Create a Tcp listener.
 mTcpListener = new TcpListener(theAddress, port);

 Console.WriteLine($"Trying to listen on {theAddress}:{port}");
 mTcpListener.Start();
 Console.WriteLine("Listening...");
 Socket socket = null;
 try
 {
     socket = mTcpListener.AcceptSocket();
 }
 catch (Exception ex)
 {
     Console.WriteLine(ex.Message);
     return;
 }
 // wait a little for the socket buffer to fill up
 await Task.Delay(20);

 int bytesAvailable = socket.Available;
 var completeBuffer = new List<byte>();
 while (bytesAvailable > 0)
 {
     byte[] buffer = new byte[bytesAvailable];
     int bytesRead = socket.Receive(buffer);
     completeBuffer.AddRange(buffer.Take(bytesRead));

     bytesAvailable = socket.Available;
 }

 byte[] receivedBytes = completeBuffer.ToArray();

 string receivedString = Encoding.ASCII.GetString(receivedBytes);

... works like a charm. ... 奇迹般有效。 The returned string is 返回的字符串是

GET /MyService/ HTTP/1.1
User-Agent: Wget/1.17.1 (cygwin)
Accept: */*
Accept-Encoding: identity
Host: 127.0.0.1:45987
Connection: Keep-Alive

So, as a workaround, I could implement my own http request parser and response generator... not that I like being forced to reinvent the wheel. 因此,作为一种解决方法,我可以实现我自己的http请求解析器和响应生成器...而不是我喜欢被迫重新发明轮子。

I just had the same problem, and it was caused by a URL ACL. 我刚遇到同样的问题,它是由URL ACL引起的。

From an elevated command prompt 从提升的命令提示符

netsh http show urlacl will show all URL ACLs netsh http show urlacl将显示所有URL ACL

netsh http delete urlacl http://+:1234/ will delete the URL ACL with the URL http://+:1234/ netsh http delete urlacl http://+:1234/将使用URL http://+:1234/删除URL ACL

netsh http add urlacl url=http://+:1234/ user=Everyone will add a URL ACL that any local user can listen on (normally this should use the network service account) netsh http add urlacl url=http://+:1234/ user=Everyone都会添加一个任何本地用户都可以监听的URL ACL(通常这应该使用网络服务帐户)

This URL needs to match the prefix in your HttpListener . 此URL需要与HttpListener中的前缀匹配。

If you're only listening on localhost, you don't need a URL ACL. 如果您只是在侦听localhost,则不需要URL ACL。

Normally not having the correct the URL ACL results in a permissions error when starting the listener. 通常,没有正确的URL ACL会在启动侦听器时导致权限错误。 I'm not sure what the specific situation is that causes it to get past this but then return 503 Service Unavailable on GetContext . 我不确定具体情况是什么导致它超过此但是然后在GetContext上返回503服务不可用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM