【问题标题】:How to properly recycle my TCP port using HttpListener c#如何使用 HttpListener c# 正确回收我的 TCP 端口
【发布时间】:2018-07-27 19:08:52
【问题描述】:

根据 cmets 和我自己的测试,我确信我的初始 TCP 端口没有清除,我真的不知道如何补救。

我尝试在我的刷新方法中遍历前缀:

foreach (string item in myWebListener.Prefixes) {
    if (item.Contains("http://127.0.0.1:5000")) {
        myWebListener.Prefixes.Remove(item);
    }
}

这并没有对行为造成任何明显的改变。

Web 日志中唯一弹出的其他内容是关于 favicon.ico 文件的内容,可能另一个浏览器线程正在捕获我的连接,试图检索它并准备提供它作为一个异步回调来完成任务,尽管我没有提供它,所以这种思路对我来说很有意义(如何在我的字节流中提供一个 favicon.ico 文件作为嵌入式资源是我的下一个研究项目)。

如果这显示没有变化,我的下一个研究项目将尝试利用 TCPListener:

我遇到了这个Q/A,但它真的没有帮助我,因为我不熟悉我在这里所做的 TCP 方式,而且解决方法看起来类似于我已经尝试过的我的原始代码。

在链接的问答中提到了 using 语句,我猜它看起来像:

using(TCPListener myTCPListener = new TCPListener()) {
    //Set the necessary TCP statements here.
    //Do what I already did with my existing code here.
}

我的大脑能带我到现在为止,这听起来离这里的因素还很远吗?


以下是原始问题内容


我已成功访问我正在运行的 C# HttpListener localhost 服务器,并成功将信息发送回本地请求浏览器页面。

但在第一次之后,我完全锁定了浏览器网页等待新的响应。

我在 VS 上调试没有错误,所以我什至不知道下一步该往哪里看;这就是我在这里的原因。

我的希望是,有人可以阐明如何在内部刷新我的服务器,因此当需要新查询时,我可以像第一次一样响应它。

我正在使用 http get 方法来调用它,所以调用看起来类似于以下内容:

"http://127.0.0.1:5000/?param1=searchForThings&param2=itemToSearchFor";

我必须删除很多专有代码,但这是正在发生的事情:

public class myWebServer {
    public myWebServer() {
            refresh();
            //The Global is being set When the API 
            //  Loads & is referenced here
            ev1 = _MyGlobalEvents.ev1
    }

    public static HttpListener myWebListener { get; set; }
    public static HttpListenerContext context { get; set; }
    public static AsyncCallback myGetCallback { get; set; }
    public static HttpResponseMessage myResp { get; set; }
    public static Stream output { get; set; }
    public static MyAPIDefinedEventType ev1 { get; set; }

    public static void refresh() {
        if (myWebListener != null) {
                myWebListener.Stop();
                myWebListener.Close();
        }
        if (output != null) { output.Dispose(); }
        if (myGetCallback != null) { myGetCallback = null; }
        myWebListener = new HttpListener();
        myGetCallback = new AsyncCallback(processRequest);
        myWebListener.Prefixes.Add("http://127.0.0.1:5000/");
        myWebListener.Start();
        myResp = new HttpResponseMessage(HttpStatusCode.Created);
        myWebListener.BeginGetContext(myGetCallback, myResp);
    }

    public static void processRequest(IAsyncResult result) {
        context = myWebListener.EndGetContext(result);
        context.Response.KeepAlive = true;
        myResp = new HttpResponseMessage(HttpStatusCode.Accepted);
        context.Response.StatusCode = (int)HttpStatusCode.Accepted;
        output = context.Response.OutputStream;
        string label = context.Request.QueryString["param1"];
        string fiStr = context.Request.QueryString["param2"];

        if (label != null || label != "" || label.Contains("\n") == false) {
            int pass1 = 0;
            int pass2 = 0;
            try {
                int myInt = label.ToCharArray().Length;
                pass1 = 1;
            } catch { }
            if (pass1 > 0) {
                try {
                    int myInt2 = fiStr.ToCharArray().Length;
                    pass2 = 1;
                } catch { }
            }
            if ((pass1 == 1 && pass2 == 0) || (pass1 == 1 && pass2 == 1)) {
                pass1 = 0;
                pass2 = 0;
                if (label == "searchForThings" && (fiStr != null && fiStr != "")) {
                    string respStr = "<html><body><div id=\"status_msg\" style=\"display:inline;\">" + fiStr + "</div></body></html>";
                    byte[] respBuffer = Encoding.ASCII.GetBytes(respStr);
                    context.Response.StatusCode = (int)HttpStatusCode.Accepted;
                    output.Write(respBuffer, 0, respBuffer.Length);
                    _MyGlobalEvents.searchStr = fiStr;
                    ev1.Raise();
                }
            }
        }
    }

    //When the Custom Event is done processing it runs something like the 
    //following to clean up and finalize
    public void _processSearch(string resultStr) { processSearch(resultStr); }
    public static void processSearch(string resultStr) {
        string respStr = "<html><head>" +
                        "<style type=\"text/css\">" +
                        "tr.dispRow{ display:table-row; }\n" +
                        "tr.noRow{ display:none; }" +
                        "</style>" +
                        "</head>" +
                        "<body>" +
                        resultStr +
                        "</body></html>";
        byte[] respBuffer = Encoding.ASCII.GetBytes(respStr);
        output.Flush();
        context.Response.StatusCode = (int)HttpStatusCode.OK;
        output.Write(respBuffer, 0, respBuffer.Length);
        output.Close();
        context.Response.KeepAlive = false;
        context.Response.Close();
        refresh();
    }
}

public static class _MyGlobalEvents {
    public static string searchStr { get; set; }
    public static MyAPIDefinedEventType ev1 { get; set; }
}

【问题讨论】:

  • 我认为你做的事情与人们通常做的不同。通常在 Main 中有一个无限循环等待请求并为每个请求创建一个线程(限制线程)并让线程处理请求。或者让您的生活更轻松 全部查看 webapi docs.microsoft.com/en-us/aspnet/web-api/overview/…
  • @Mightee 我仅限于 API 的实现,而这段代码实际上是加载项的一部分。我可以使用各种标准的网络服务器,但我特别需要它来运行它运行的软件,所以......这个评论并没有真正帮助我。另外,HttpListener 是一个众所周知的 .NET 模块,它已经存在了很长一段时间,知识渊博的人都理解它ref #1ref #2
  • 哇,你真的不好。无论如何,正如我之前在评论中提到的,如果你想处理多个请求,你应该做一个无限循环。检查这个问题:stackoverflow.com/questions/9034721/…
  • 您似乎在processRequests 的末尾缺少BeginGetContext。由于你只调用一次,回调只会被触发一次。
  • @Mightee,我不想听到我的声明对你不利,因为我只是想说明在这种情况下,这不是我非常愿意放弃的方法还没有。

标签: c# http tcp tcplistener httplistener


【解决方案1】:

我的特殊问题实际上是来自浏览器的 favicon.ico 文件请求锁定了连接。

早些时候,我注意到我的服务器被击中了两次,这就是为什么我设置了我的标志以确保我只根据我期望的 URL 对实际的 Get 请求进行操作.. .

否则,URL 会作为空白字符串出错(原来这是 favicon.ico 请求正在发出 - 令人恼火,因为当字符串完全为空时,您不知道如何解决它)。所以我忽略了它,不去碰我不懂的东西。

好吧,我可以忽略这个请求,因为浏览器正在等待它的响应。我所要做的就是在我的代码中添加一个 else 部分,如果我的标志选项不满足,则执行该部分,并在发生这种情况时关闭、处理和刷新连接。

这个Q/A 确实很好地描述了问题的固化解决方案,但是我的 Exception.Message 是空白的,也没有真正在那里得到解决,所以我很高兴我能在这里记录它,希望任何可能遇到同样问题的人都会发现答案更加困难。

至于 PhillipH 提供的答案,事实证明这对我最有帮助,因为它向我表明我需要检查网络流量事件发生的情况。

但是,我无法真正使用该用户建议的工具,但找到​​了 Google Chrome 内置的替代方法 chrome://net-internals/。只需在 chrome 的地址栏中输入并执行即可。

无论如何,这对我来说是一个完整的答案,但是 PhillipH 你应该得到它,因为它让我朝着正确的方向前进。

【讨论】:

    【解决方案2】:

    “但是在第一次之后,我完全锁定了浏览器网页等待新的响应” - 你是说浏览器发送Http请求但没有响应时看到错误?

    我建议下载和使用 Telerik Fiddler(免费)来查看客户端和服务器之间实际发送和接收的内容。

    正如其他响应者所说 - 这不是 HttpListener 的正常模式,我猜你在服务器上的 TCP 端口缓存有问题,并且你的 .Stop() 和 .Close() 方法没有释放TCP 端口(Windows 缓存它)

    【讨论】:

    • 这个答案对我非常有帮助,因为它让我看到了一些问题;但是它并没有完全回答我原来的问题。我如何实际刷新端口(解除阻止我的服务器/杀死并回收我的端口/等等......)。我运行它的 API 不允许运行多个线程,所以我真的必须处理我的问题的这个阻塞方面。
    猜你喜欢
    • 2010-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-18
    • 2011-05-19
    • 2013-11-07
    • 1970-01-01
    • 2011-10-22
    相关资源
    最近更新 更多