remoting通过路由,防火墙解决方案。

Introduction

" When I create a CAO from inside my network/router, everything works fine. However, when I have a client outside my network that creates a CAO inside the network, it fails the first time I call a function. What am I doing wrong!?!?!"

I hear this question on newsgroups and bulletin boards almost every day. The answer is actually pretty straightforward although it can get deeper if you wish to spice up the functionality.

Why this happens

When a CAO is created the server returns a URI that points to the unique instance of the CAO on the server. This is how the server knows the unique instance you are using. (This is also why its very difficult to load balance CAO objects). The URI that the server sends back contains either the IP that it thinks it is or the IP you tell it that it really is.

How to fix it (the quick fix)

The simple fix for this that will work on most setups is to set the 'machineName' property of the channel on the server to the EXTERNAL ip that the client sees. This allows the server to return the external ip instead of its local internal IP. Typically you want to set the machineName equal to the EXTERNAL ip. This is the IP that your firewall or router has. This is also the IP that machines will see from outside your LAN when they go to connect to your remote object.

For example, for a TcpChannel you would do the following on the SERVER side of your code.

	IDictionary prop = new Hashtable();
prop["port"] = 4000;
prop["machineName"] = "myexternalip.com";
tcpChannel = new TcpChannel(prop, null, null);
ChannelServices.RegisterChannel(tcpChannel);


That's all you need. Your server should now work perfectly from outside your LAN/Firewall/Router.

There is a second method of fixing this problem which is much more complete, yet more complicated

A complete solution

What do I do if I need to access the server from both inside the LAN and outside without having to set machine name? Or what if I don't know what the machineName will be and I don't want to bother my users with having to know something mildly technical like that? The machineName fix is ok, but it leaves a lot to be desired in many situations. This can be a real problem if its for a home or small business application where you may or may not have someone with a clue. Wouldn't it be easier if we just had a solution that worked everywhere? Well your in luck! Because thats exactly what this is. This solution uses the IP that the CLIENT sees the server as (which you of course know or the client wouldn't be able to even connect to the server in the first place.

This solution also works very well where you have a multi-homed server (common in corporate intranets). A server with multiple NIC cards may be seen by many IPs each requiring a different route in and out of the server. This will work perfectly for that situation as well.

So how do I create a CAO on a server and have it work regardless if I'm inside or outside the local network? The answer lies in a rarely used class called the TrackingHandler. The basic process is as follows. We create our SAO Class Factory first, then when we go to create our CAO, we send the IP the client sees the server as in the creation call. This then puts the information in the CallContext where the tracking handler picks it up when it is fired during CAO creation and return. The tracking handler takes the URI that is being returned and replaces the server address with the address you have told the server you see it as. From then on, your CAO will work flawlessly against the server, you never have to do another thing.

This diagram demonstrates a sample where the server has multiple network cards and multiple entry points.

CAO's instanced on the three different networks will see the server by >3< different distinct IP's! MachineName won't fix this problem without creating multiple channels. The fix for this problem is to have CAO return a URI upon creation that takes into account the way the client sees the server.

Line's into the server represent the IP the client computer ses the server as.

Now that I've given you the overview, lets get into the details.

First, this approach assumes that you are using a simple factory pattern to create your CAO. You can see an explanation of factory pattern CAO creation in my article here . This will also work if you use interfaces instead of abstract classes but for the purposes of this article we will focus on abstract class share type.

The factory create method for your CAO should accept a string. This string will hold the address the client sees the server as. Define it first in the abstract class then implement it in your SAO factory implementation. I included a regular factory implementation along with the address based one so you can see both approaches.

// share.dll abstract SAO factory
namespace ShareDLL
{
public abstract class SAOCAOClassFactoryDef : MarshalByRefObject
{
public abstract CAOClassDef CreateCAOClass();
public abstract CAOClassDef CreateCAOClass( string strIP );
}
}

// implementation SAOCAOClassFactory.cs
public class SAOCAOClassFactory : ShareDLL.SAOCAOClassFactoryDef
{
public override CAOClassDef CreateCAOClass()
{
// this is important to clear out or it will get the address you left in on a previous factory call
CallContext.FreeNamedDataSlot( "ObservedIP" );
return new CAOClass(); // class factory create
}

public override CAOClassDef CreateCAOClass( string strAddress )
{
CallContext.SetData("ObservedIP", strAddress);
return new CAOClass(); // class factory create
}
}

 

Now that we have the address in the call context we can implement our tracking handler. Our tracking handler will grab the address out of the call context and insert it into the URI.

// trackinghandler.cs in server.exe
public class ExampleTrackingHandler : ITrackingHandler
{
// Notify a handler that an object has been marshaled.
public void MarshaledObject(Object obj, ObjRef or)
{
// Assumption: We have a server channel sink that sets a call context flag
// called "ObservedIP" whenever we are processing a remote request
object ObservedIP = CallContext.GetData("ObservedIP");

// for local clients we don't do anything here
// if they don't specify the remote IP then we just use the servers IP
if (ObservedIP == null)
return;

if (or.ChannelInfo == null)
return;

string strAddress = (string)ObservedIP;

for ( int i = or.ChannelInfo.ChannelData.GetLowerBound(0);
i <= or.ChannelInfo.ChannelData.GetUpperBound(0); i++ )
{
// Check for the ChannelDataStore object that we don't want to copy
if(or.ChannelInfo.ChannelData[i] is ChannelDataStore)
{
// Personally I don't know why ChannelURIs is an array... I am only
// familiar with there being one URI in each ChannelDataStore object
foreach(string uri in ((ChannelDataStore)or.ChannelInfo.ChannelData[i]).ChannelUris)
{
// this will get the first part of the uri
int nOffset = uri.IndexOf( "//" ) + 2;

string strNewUri = uri.Substring( 0, nOffset );
strNewUri += strAddress;
nOffset = uri.IndexOf( ":", nOffset );
strNewUri += uri.Substring( nOffset, uri.Length - nOffset );
string[] strarray = new string[1] { strNewUri };

ChannelDataStore cds = new ChannelDataStore( strarray );
or.ChannelInfo.ChannelData[i] = cds;
}
}
}
}
}

We have our class factory and our tracking handler, the last thing we need to do is make sure we register our tracking handler during the registration in our server. We do that with the simple RegisterTrackingHandler.

ChannelServices.RegisterChannel( new TcpChannel( 4000 ) );
// this will handle converting the returned CAO uri to the correct server IP
TrackingServices.RegisterTrackingHandler(new ExampleTrackingHandler());

Type thisType = Type.GetType("Server.SAOCAOClassFactory,Server");
RemotingConfiguration.RegisterWellKnownServiceType(thisType, "SAOCAOClassFactoryURI",
WellKnownObjectMode.SingleCall );

 

 

 

源文出自:http://www.glacialcomponents.com/ArticleDetails/CAOMN.aspx

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Remoting客户是指使用远程调用技术进行通信的客户端。远程调用是一种在分布式系统中的通信方式,它允许在不同的计算机之间进行方法的调用和数据的传输。 Remoting客户通过建立与远程服务器的连接,可以像调用本地对象一样调用远程对象的方法。这样的客户端可以将请求发送给远程服务器,获得结果并将其返回给调用方。Remoting客户端可以通过网络传输数据,实现平台和语言的通信。 Remoting客户端通常通过使用远程代理(Proxy)来访问远程对象。远程代理充当了客户端和服务器之间的中间层,隐藏了底层通信的细节。客户端通过远程代理来调用远程对象的方法,而不需要了解底层的网络通信协议或者具体的通信细节。 Remoting客户端还可以通过配置文件或者编程方式来指定远程服务器的地址和端口以及其他的通信参数。这样的配置方式使得客户端可以灵活地连接到不同的远程服务器上。 在使用Remoting客户端时,需要注意网络的稳定性和安全性。网络不稳定可能造成通信中断或者性能降低,而网络安全问题可能导致数据泄露或者被篡改。因此,在设计和实现Remoting客户端时,需要考虑这些问题,并采取相应的措施。 总之,Remoting客户端是一种使用远程调用技术进行通信的客户端,它可以像调用本地对象一样调用远程对象的方法。通过使用远程代理,客户端可以隐藏底层通信的细节,并通过配置文件或者编程方式连接到远程服务器。在使用Remoting客户端时,需要注意网络的稳定性和安全性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值