【问题标题】:Identifying the client during a .NET remoting invocation在 .NET 远程调用期间识别客户端
【发布时间】:2010-10-06 08:59:15
【问题描述】:

鉴于这个 MarshalByRef 类:

public class MyRemotedClass : MarshalByRef
{
  public void DoThis()
  {
     ...
  }
  public void DoThat()
  {
     ...
  }
}

客户端代码:

MyRemotedClass m = GetSomehowMyRemotedClass();
m.DoThis();
m.DoThat();

我可以让多个客户同时做同样的事情。 我想区分客户。 如何在远程访问的方法中识别远程调用是由谁执行的? 例如,我可以记录谁做了什么。 (其实我并不需要追溯真实的客户信息,我只是希望能够对客户的调用进行分组。)

[编辑以添加更多背景信息]

我需要处理大量代码,包括属性。因此扩展输入参数列表不是一种选择。

【问题讨论】:

    标签: .net multithreading remoting


    【解决方案1】:

    您可以做的事情之一是通过实现IServerChannelSinkProvider,通过 IP 地址识别客户端。

    将此类添加到您的远程主机项目中:

    ClientIPServerSinkProvider.cs

    using System;
    using System.Collections;
    using System.IO;
    using System.Runtime.Remoting;
    using System.Runtime.Remoting.Messaging;
    using System.Runtime.Remoting.Channels;
    using System.Threading;
    using System.Net;
    
    namespace MyRemotingEnvironment
    {
        public class ClientIPServerSinkProvider : 
            IServerChannelSinkProvider
        {
            private IServerChannelSinkProvider _nextProvider = null;
    
            public ClientIPServerSinkProvider()
            {
            }
    
            public ClientIPServerSinkProvider(
                IDictionary properties, 
                ICollection providerData)
            {
            }
    
            public IServerChannelSinkProvider Next
            {
                get { return _nextProvider; }
                set { _nextProvider = value; }
            }
    
            public IServerChannelSink CreateSink(IChannelReceiver channel)
            {
                IServerChannelSink nextSink = null;
    
                if (_nextProvider != null)
                {
                    nextSink = _nextProvider.CreateSink(channel);
                }
                return new ClientIPServerSink(nextSink);
            }
    
            public void GetChannelData(IChannelDataStore channelData)
            {
            }
        }
    
    
    
        public class ClientIPServerSink : 
            BaseChannelObjectWithProperties, 
            IServerChannelSink, 
            IChannelSinkBase
        {
    
            private IServerChannelSink _nextSink;
    
            public ClientIPServerSink(IServerChannelSink next)
            {
                _nextSink = next;
            }
    
            public IServerChannelSink NextChannelSink
            {
                get { return _nextSink; }
                set { _nextSink = value; }
            }
    
            public void AsyncProcessResponse(
                IServerResponseChannelSinkStack sinkStack, 
                Object state, 
                IMessage message, 
                ITransportHeaders headers, 
                Stream stream)
            {
                IPAddress ip = headers[CommonTransportKeys.IPAddress] as IPAddress;
                CallContext.SetData("ClientIPAddress", ip);
                sinkStack.AsyncProcessResponse(message, headers, stream);
            }
    
            public Stream GetResponseStream(
                IServerResponseChannelSinkStack sinkStack, 
                Object state, 
                IMessage message, 
                ITransportHeaders headers)
            {
    
                return null;
    
            }
    
    
            public ServerProcessing ProcessMessage(
                IServerChannelSinkStack sinkStack, 
                IMessage requestMsg, 
                ITransportHeaders requestHeaders, 
                Stream requestStream, 
                out IMessage responseMsg, 
                out ITransportHeaders responseHeaders, 
                out Stream responseStream)
            {
                if (_nextSink != null)
                {
                    IPAddress ip = 
                        requestHeaders[CommonTransportKeys.IPAddress] as IPAddress;
                    CallContext.SetData("ClientIPAddress", ip);
                    ServerProcessing spres = _nextSink.ProcessMessage(
                        sinkStack, 
                        requestMsg, 
                        requestHeaders, 
                        requestStream, 
                        out responseMsg, 
                        out responseHeaders, 
                        out responseStream);
                    return spres;
                }
                else
                {
                    responseMsg = null;
                    responseHeaders = null;
                    responseStream = null;
                    return new ServerProcessing();
                }
            }
    
    
        }
    }
    

    然后,当您启动远程主机时,请执行以下操作:

    BinaryServerFormatterSinkProvider bp = new BinaryServerFormatterSinkProvider();
    ClientIPServerSinkProvider csp = new ClientIPServerSinkProvider();
    csp.Next = bp;
    Hashtable ht = new Hashtable();
    ht.Add("port", "1234"); // Your remoting port number
    TcpChannel channel = new TcpChannel(ht, null, csp);
    ChannelServices.RegisterChannel(channel, false);
    
    RemotingConfiguration.RegisterWellKnownServiceType(
        typeof(MyRemotedClass), 
        "MyRemotedClass.rem", 
        WellKnownObjectMode.SingleCall);
    

    在您的方法调用中,您可以通过以下方式访问客户端的 IP 地址:

    public class MyRemotedClass : MarshalByref
    {
        public void DoThis()
        {
            string clientIP = CallContext.GetData("ClientIPAddress").ToString();
        }
    }
    

    【讨论】:

    • 获取客户端IP真的这么复杂吗?
    • @dboarman - 这是唯一的方法。但是,如果您已经习惯于编写自己的通道接收器类,那么它就会成为远程生活的正常组成部分。
    • 是的,对我来说不幸的是,这确实是我第一次涉足远程处理...我现在暂时搁置。当我可以实现 Marc Gravell 的 protobuf-net 时,我并不热衷于使用 Remoting :) 我现在的方向略有不同......谢谢你的帮助。
    • @dboarman - protobuf-net 不只是一个序列化程序吗?即,您构建到您选择的服务基础架构中,例如远程处理或 wcf?我认为这不会解决诸如获取客户端 IP 地址之类的问题。
    • @Kev:按照我的理解(来自 Marc Gravell),我可以在标准 Tcp 套接字上使用 protobuf-net。 Tcp 套接字服务器很容易通过 IP 地址了解客户端 ID。
    猜你喜欢
    • 2016-10-05
    • 1970-01-01
    • 2013-07-03
    • 2016-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多