生产就绪的多线程 C# http 服务器

2024-02-14

我在 c# .NET 中实现了一个 HTTP 服务器:

public class HttpServer
{
    private HttpListener listener;

    public HttpServer()
    {
        listener = new HttpListener();
        listener.Prefixes.Add("http://localhost:8080/");
    }

    public void Start()
    {
        lock(this) {
            listener.Start();
            AsyncProcessing(listener);
        }
    }

    public void Stop()
    {
        lock (this) {
            listener.Stop();
        }
    }

    private void AsyncProcessing(HttpListener listener)
    {
        if (listener == null)
            return;

        listener.BeginGetContext(new AsyncCallback(Callback), listener);
    }

    private void Callback(IAsyncResult result)
    {
        HttpListenerContext context = null;

        lock(this) {
            HttpListener listener = (HttpListener)result.AsyncState;
            if (!listener.IsListening)
                return;

            context = listener.EndGetContext(result);

            AsyncProcessing(listener);
        }

        /* handle request */
    }
}

我对这个实现有一些疑问:

  • 我到处添加了一些锁来防止竞争条件,但我很困惑:这些真的需要吗?我在文档中读到所有公共非静态方法都不是线程安全的。为什么我没有看到考虑这个事实的代码?
  • HttpListenerContext 的行为如何?他与 HttpListener 有某种连接吗?或者我可以同时使用多个 HttpListenerContexts 吗?
  • 我听说 HttpListener 还没有为生产系统做好准备,但我从未见过支持这一说法的论据。到底是真是假?
  • 还有其他我没有提到的事情我应该考虑吗?

感谢您的想法


请记住,我不是多线程方面的专家,因此您应该尽可能小心地验证我所说的任何内容。

如果还有其他人knows,并且想窃取我的整个答案并编辑或更正细节,请随意这样做。

我们来一一解答您的疑问:

我到处添加了一些锁来防止竞争条件,但我很困惑:这些真的需要吗?我在文档中读到所有公共非静态方法都不是线程安全的。为什么我没有看到考虑这个事实的代码?

嗯,是的,也不是。锁通常用于防止多个线程同时访问同一数据结构,因为这会破坏数据结构。考虑在一个线程上对数组进行排序,然后在另一个线程的中间插入一个元素,正确计时这两个线程会破坏数组的内容。

现在,在您的代码中您正在锁定this这绝不是一个好主意。外部代码might还对同一个对象进行锁定,这是您无法控制的,因此为了创建生产准备就绪代码,我不会那样做。

如果您的代码中需要锁,我将构造特定的锁对象并使用它们。

换句话说,添加以下内容:

private readonly object _Lock = new object();

然后你所到之处lock(this)替换为lock(_Lock)反而。这样,如果需要的话,您还可以拥有多个锁。

至于实际上是否需要锁,我并不是 100% 确定。我不确定的是,您在调用 Stop 之前锁定,并且您在回调中锁定,并在锁内检查侦听器是否仍在运行。

这将阻止您在接受请求之后但在实际处理请求之前停止侦听器。换句话说,听起来您会阻止在仍在处理打开的请求的情况下关闭服务器。

但是,不,您不会阻止这种情况,因为您可能会在回调中留下锁定部分后停止服务器,但在注释代码完全执行期间或之前,所以您仍然会遇到这个问题。

However它还意味着您已经有效地序列化了一些回调方法,即调用 EndGetContext 并重新启动 BeginGetContext 循环的部分。这是否是一个好的模式,我不知道。

HttpListenerContext 的行为如何?他与 HttpListener 有某种连接吗?或者我可以同时使用多个 HttpListenerContexts 吗?

这里我就做一个猜测。该类没有返回侦听器类的引用,or,它有一种线程安全的方式与之合作。

如果对请求/响应数据的每次访问都必须序列化,那么基于线程的 http 侦听器系统就不那么重要了。

无论如何,如果有疑问,请检查您正在访问的上下文类的方法和/或属性的文档,如果您需要采取措施确保线程安全,文档会这么说。

我听说 HttpListener 还没有为生产系统做好准备,但我从未见过支持这一说法的论据。到底是真是假?

(参见问题评论)

还有其他我没有提到的事情我应该考虑吗?

多线程代码是hard来写。从你的问题来看,我斗胆猜测你做的还不够多,说实话,虽然我做了很多,但我还是感觉如履薄冰。

我的建议如下:

  • Do you really需要多线程吗?
  • 您是否有其他对此有更多了解的同事可以为您提供帮助?
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

生产就绪的多线程 C# http 服务器 的相关文章

随机推荐

  • 以集群模式在同一物理节点上运行 Storm nimbus 和supervisor

    我现在有一个包含 2 个物理节点的 Storm 集群 我在跑storm nimbus在节点 1 上和storm supervisor在节点 2 上 看起来我的所有拓扑都仅在节点 2 管理节点 上运行 我也应该在节点 1 上运行主管吗 Tha
  • 如何使用 for_each 删除 STL 映射中的每个值?

    假设我有一个 STL 映射 其中的值是指针 并且我想将它们全部删除 我如何表示以下代码 但使用 std for each 我很高兴找到使用 Boost 的解决方案 for stdext hash map
  • 管理器中缺少应用程序图标

    我最近迁移了我的应用程序以支持 iOS7 并在此过程中更新了我的应用程序图标以使用资产目录 这一切在应用程序中都运行良好 但是 在 Organizer 和 TestFlight 中 我的应用程序图标丢失了 同样的情况也发生在 TestFli
  • Google Maps API v3 向每个标记添加信息窗口

    注意 我使用的是 Google Maps API v3 我正在尝试为我在地图上放置的每个标记添加一个信息窗口 目前我正在使用以下代码执行此操作 for var i in tracks racer id data points values
  • 从 SJSIR “手动”构建 JS

    我需要在运行时从 sjsir 文件构建一个 js 文件来实现插件系统 这样就无法在编译时与我的其余编译一起完成 我曾经在 0 6 3 中使用以下代码实现相同的过程 但它似乎已被弃用 您建议使用什么算法来实现与 0 6 13 相同的操作 谢谢
  • 更改博客主题(blogdown+netlify)

    我按照 Yihui 的教程并使用创建了一个网站blowdown github and netlify 现在 我想更改我的网站的主题 问题是我有几篇文章产生了很多情节 因此 当我在本地创建一个新网站并添加我的帖子时 git push失败 我怀
  • Xcode 12 Beta - 找不到模拟器运行时

    我已经安装了 Xcode 12 beta 2 我尝试通过 Mac OS Catalina 上的 Jenkins 运行我们的 xamarin 项目 它失败并出现以下错误 当我从 Mac Visual studio 构建相同的项目时 它成功了
  • 有没有办法在网页开发中使用加色混合?

    我有一个可以使用的网页设计加法混色 http en wikipedia org wiki Additive color 想要的效果是 红色方块覆盖绿色方块 重叠区域呈现黄色 有没有什么好方法可以使用标准工具 CSS CSS 透明度 不透明度
  • 内联块+最小/最大宽度行为

    我在许多浏览器 FF Opera Ie 中看到我给它们的元素 内联块 和 最小 最大宽度 它们的宽度自动设置为 最小宽度 而不是最大宽度 如预期的那样 这是正常行为吗 我可以用CSS方式解决它 具有最大宽度的内联块元素 吗 我了解 floa
  • 快速输入输出功能

    define getcx getchar unlocked inline void inp int n fast input function n 0 int ch getcx int sign 1 while ch lt 0 ch gt
  • 为什么 tkinter 的 after() 函数会冻结我的窗口?

    我正在使用创建 dodger 的副本tkinter 我面临着计时对象移动的问题 有人告诉我时间模块不能很好地工作tkinter 因此我应该使用after 反而 但是 我面临着同样的问题after 功能就像我对时间模块所做的那样 这是我的代码
  • 特定git命令的颜色输出

    我正在编写一个运行 git 命令并捕获输出的工具 并且我希望将输出着色 Git 注意到该工具不是终端 因此color ui需要设置为always 我真的不想在全局 存储库配置文件中设置它 因为它会与使用 git 的其他程序混淆 这git b
  • 循环访问 Azure 管道中的变量

    我有一个文本文件 其中有两个名称client1 and client2 我有一个 Powershell 脚本来读取文本文件 我对它的理解是它已经创建了一个数组 clientvariable Get Content Path FilePath
  • 计划错误:尚未使用 Cloud Resource Manager API

    当我尝试跑步时 steps id Plan Terraform name hashicorp terraform light args plan 在 Cloud Build 中 我收到错误 Error Error reading Proje
  • 垃圾收集器对java中的静态变量或方法起作用吗?

    我正在创建一个示例演示程序 以便让我了解如何使用垃圾收集器在 java 中释放静态变量 方法的引用 我使用弱引用是为了不阻止垃圾收集器 Class Sample public class Sample private static Stri
  • 如何激活 Autodesk Forge Snapper?

    我正在尝试激活自查看器版本 7 3 以来实施的新 Snapper 扩展 所以我像这样加载扩展 viewer loadExtension Autodesk Snapping 似乎有效 之后 我尝试访问类似的描述方法 但总是收到此错误 getS
  • PopupWindow 上的视图可以显示 PopupMenu 吗?

    在 Android API11 中 我在 PopupWindow 内显示一个按钮 我想在单击按钮时显示 PopupMenu 而不关闭 PopupWindow 这有可能吗 我正在实例化并初始化 PopupMenu 但是当我调用 popupMe
  • Javascript ES6 - 在不同的 .js 文件中导入函数或变量之前等待模块完成执行

    我是 ES6 和导入 导出模块的新手 我对如何实现我想要的东西感到困惑 我有一个 js 文件用于初始化 SDK 并且必须等待 dom 内容首先加载 我还有其他较小的 js 文件 我想在其中编写从第一个文件引用 导入应用程序对象的方法 但是
  • 如何解决 MalformedResponse 必须设置“final_response”。动作模拟器出错

    您好 当我尝试测试我的测试应用程序时 它会停止并显示 My test app isn t responding right now Try again soon When I check validation error tab I not
  • 生产就绪的多线程 C# http 服务器

    我在 c NET 中实现了一个 HTTP 服务器 public class HttpServer private HttpListener listener public HttpServer listener new HttpListen