C#:沙箱和性能 (MarshalByRefObject)

发布于 2024-11-14 20:33:05 字数 560 浏览 1 评论 0原文

我用 C# 编写了一个非常基本的 Web 服务器,它加载自定义模块来处理对特定域名的请求,如配置文件中指定的那样。自定义模块被加载到新的 AppDomain 中,因为我需要能够动态卸载它们(也有利于安全性)。因为模块被加载到新的 AppDomain 中,所以所有参数和返回类型都是 MarshalByRefObject。这工作正常,我传递了一个继承自 MarshalByRefObject 的 HttpRequest 对象,并返回一个由 Web 服务器发送回客户端的 LinkedList。

所有这些都运行良好,但很多数据作为 byte[] 传递,我相信 MarshalByRefObject 的代理会将所有字节从新 AppDomain 复制到主 AppDomain,而不是直接访问它们。因此,如果我的说法是正确的,如果其中一个模块发送 5MB 文件作为响应,那么将在模块中加载/生成 5MB,然后从模块 AppDomain 复制到主 AppDomain,最后通过套接字发送返回给客户端。

所以,我的问题是:我可以以某种方式解决这个问题,这样它就不会在 AppDomain 之间复制太多数据吗?或者是否有更好的方法来执行此操作而不使用 MarshalByRefObject?

I've written a very basic web server in C# that loads custom modules that handle requests to a specific domain name, as specified in a config file. The custom modules are loaded into a new AppDomain because I need the ability to unload them dynamically (good for security, too). Because modules are loaded into a new AppDomain all parameters and return types are MarshalByRefObject. This works fine and I pass a HttpRequest object that inherits from MarshalByRefObject and return a LinkedList that is sent back to the client by the web server.

All of this works well, but a lot of the data is passed as byte[] and I believe the proxy for MarshalByRefObject will copy all of the bytes from the new AppDomain to the main AppDomain instead of accessing them directly. So, if I'm right about this, if one of the modules would send a 5MB file as a response then 5MB would be loaded/generated in the module, then copied from the modules AppDomain to the main AppDomain and finally sent through the socket back to the client.

So, my question is: can I get around this somehow so it doesn't copy so much data between AppDomain's? Or is there a better way to do this that doesn't use MarshalByRefObject?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

倾其所爱 2024-11-21 20:33:05

字符串是每个进程而不是每个应用程序域(出于性能原因)。如果传递 html/xml(而不是二进制数据),您可以更改 api 以使用字符串而不是字节 []。您甚至可以支持常见情况下的字符串和二进制情况下的 byte[]。

Strings are per-process rather than per-appdomain (for performance reasons). If html/xml are being passed around (and not binary data), you could change your api to use Strings instead of byte []. You might even be able to support strings in the common case and byte[] in the binary cases.

春庭雪 2024-11-21 20:33:05

我最终将 SocketInformation 传递给新的 AppDomain 并在那里创建一个新的套接字对象(在新的 AppDomain 中)。

在我的“沙盒包装对象”中,我有这个功能:

internal class Sandbox
{
    private AppDomain _AppDomain;
    private WebApplicationProxy _Proxy;

    public Sandbox(string assemblyFile)
    {
        _AppDomain = AppDomain.CreateDomain(Guid.NewGuid().ToString());
        _Proxy = (WebApplicationProxy)_AppDomain.CreateInstanceAndUnwrap(
                                                    Assembly.GetExecutingAssembly().FullName,
                                                    "WebServer.WebApplication.Proxy");
        _Proxy.Initialize(assemblyFile);
    }
    public void SendResponse(Socket client, HttpRequest request)
    {
        SocketInformation clientInfo = client.DuplicateAndClose(Process.GetCurrentProcess().Id);
        _Proxy.GetResponse(clientInfo, request);
    }
}

在新的 AppDomain“恢复”套接字中,我不确定幕后实际发生了什么...这是代码:

internal class Proxy : MarshalByRefObject
{
    private AppController _AppController;

    public void Initialize(string assemblyFile)
    {
        Assembly asm = Assembly.LoadFile(assemblyFile);
        var q = from t in asm.GetTypes()
                where t.GetInterfaces().Contains(typeof(AppController))
                      && !t.IsAbstract && t.IsClass
                select t;
        foreach (Type t in q)
        {
            _AppController = (AppController)Activator.CreateInstance(t);
        }
    }

    public void SendResponse(SocketInformation clientInfo, HttpRequest req)
    {
        Socket client = new Socket(clientInfo);

        LinkedList<byte[]> toSend = _AppController.GetResponse(client, req);

        foreach (byte[] bytes in toSend)
            client.Send(bytes);

        client.Close();
    }
}

我不确定细节调用 DuplicateAndClose 时发生的情况,或者在新域中创建新的 Socket 对象时发生的情况,但到目前为止运行良好。

I ended up passing the SocketInformation to the new AppDomain and creating a new socket object there (in the new AppDomain).

In my "Sandbox wrapper object" I have this function:

internal class Sandbox
{
    private AppDomain _AppDomain;
    private WebApplicationProxy _Proxy;

    public Sandbox(string assemblyFile)
    {
        _AppDomain = AppDomain.CreateDomain(Guid.NewGuid().ToString());
        _Proxy = (WebApplicationProxy)_AppDomain.CreateInstanceAndUnwrap(
                                                    Assembly.GetExecutingAssembly().FullName,
                                                    "WebServer.WebApplication.Proxy");
        _Proxy.Initialize(assemblyFile);
    }
    public void SendResponse(Socket client, HttpRequest request)
    {
        SocketInformation clientInfo = client.DuplicateAndClose(Process.GetCurrentProcess().Id);
        _Proxy.GetResponse(clientInfo, request);
    }
}

And in the new AppDomain "resumes" the socket, I'm not sure yet what actually happens behind the scenes... here's the code:

internal class Proxy : MarshalByRefObject
{
    private AppController _AppController;

    public void Initialize(string assemblyFile)
    {
        Assembly asm = Assembly.LoadFile(assemblyFile);
        var q = from t in asm.GetTypes()
                where t.GetInterfaces().Contains(typeof(AppController))
                      && !t.IsAbstract && t.IsClass
                select t;
        foreach (Type t in q)
        {
            _AppController = (AppController)Activator.CreateInstance(t);
        }
    }

    public void SendResponse(SocketInformation clientInfo, HttpRequest req)
    {
        Socket client = new Socket(clientInfo);

        LinkedList<byte[]> toSend = _AppController.GetResponse(client, req);

        foreach (byte[] bytes in toSend)
            client.Send(bytes);

        client.Close();
    }
}

I'm not sure about the details of what happens when DuplicateAndClose is invoked, or creating the new Socket object in the new domain, but it is working well so far.

冰葑 2024-11-21 20:33:05

如果这是 .NET 4.0 将使用 内存映射文件是一个选项吗?

If this is .NET 4.0 would using a Memory mapped file be an option?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文