您的位置:首页 > 其它

.NET Romoting 学习总结(四)—— Remoting技术细节之多通道注册

2007-01-25 16:32 567 查看
此文章转载自Sharping's Nonsense的http://www.sharping.net/CommentView,guid,9592435d-5496-45f4-a80e-d0a121d454cf.aspx

引言:如果你是一个热爱技术的人,相信看了前面几篇文章后已经迫不及待的去写代码了吧,如果你是一个乐于创新技的术追求者,你一定发现了Rremoting中的一些问题是我没讲到的。细节,又见细节,今天要探讨的就是Remoting中的细节之一——多通道注册的实现。

常常有这样的需求,我们需要在两个不同的通道完成两种不同的服务,那么回顾一下前面讲的内容,注册通道:

TcpChannel channel = new TcpChannel(8080);
ChannelServices.RegisterChannel(channel);

那么多通道呢?通常的思维模式应该是这样实现:

TcpChannel channel = new TcpChannel(8080);
ChannelServices.RegisterChannel(channel);

TcpChannel channel = new TcpChannel(9999);
ChannelServices.RegisterChannel(channel);

结果出忽意料,这样的语句在运行时检查时候会出问题,编译可以通过。
通过查阅相关资料,发现,Remoting用来区分通道的标识是来自TcpChannel的Name属性而并不是端口号,也就是说每个通道必须有不同的Name属性,这样理论上可以在创建TcpChannel实例后对其Name属性赋值再进行注册。可是在MSDN上查看TcpChannel类的Name属性原形发现这个Name属性只有get访问器,也就是说他是只读的。晕了吧~~~看来问题还要继续往上追溯。
通过查阅MSDN可以发现,其实TcpChannel有三种重载构造方法。其中一种就是我们上面的形式,还有不指定端口的,最后还有一种参数很多,我们来看看他的原形:

public TcpChannel(
IDictionary properties,
IClientChannelSinkProvider clientSinkProvider,
IServerChannelSinkProvider serverSinkProvider
);

参数说明:
properties
保存当前信道配置信息的信道属性的 IDictionary。
clientSinkProvider
IClientChannelSinkProvider,它为远程处理消息所流过的基础 TcpClientChannel 创建客户端信道 接收。
serverSinkProvider
IServerChannelSinkProvider,它为远程处理消息所流过的基础 TcpServerChannel 创建服务器信道接收。

如果你有好的编程习惯的话会知道,I打头的类型是接口类型。通过查阅资料可以知道,在.NET里Hashtable类是实现了IDictionary接口的,BinaryClientFormatterSinkProvider类实现了IClientChannelSinkProvider 接口,而 BinaryServerFormatterSinkProvider类实现了IServerChannelSinkProvider接口,至于后面两个类,可以使用构造默认构造方法来创建实例,把这两个实例做为后面两个参数即可,因为他们只是提供二进制格式化接收程序,关于这方面细节可以查阅MSDN,通道的属性主要依靠第一个参数IDictionary来区别。

我们来看看Hashtable类,在MSDN里是这样描述他的:表示键/值对的集合,这些键/值对根据键的哈希代码进行组织。键?值?听起来是不是很象数据库里的术语,对,其实他们在某种程度上是同一概念。所谓键,可以理解成字段,值可以理解成这个字段的Value(又想不到词了,只能用E文解释中文)。其实他的实现原理是Hashtable类为我们提供了一个返回类型和参数类型都是string类型的索引器,这样可以自己创建一些键/值对,那么想一想,TcpChannel类的Name属性是不是这样对应的一个Name对应一个字符串(string类型),这里Name就是键,而这个字符串就是值。另外TcpChanne类当然还少不了他的port属性。那么这样创建Hashtable类的实例:

Hashtable instance = new Hashtable();
tcpProp["name"] = "tcp9090";
tcpProp["port"] = 9090;

上面说过 Hashtable 类实现了IDictionary接口,那么程序就因该是这样:

IDictionary iChannel = new Hashtable();
tcpProp["name"] = "tcp9090";
tcpProp["port"] = 9090;

这样就构造出了第一个参数,那么多通道问题就可以解决了。我们来看完整代码,注册一个http通道和一个tcp通道.

注册Tcp通道:

IDictionary tcpProp = new Hashtable();
tcpProp["name"] = "tcp9090";
tcpProp["port"] = 9090;
IChannel channel = new TcpChannel(tcpProp,
new BinaryClientFormatterSinkProvider(),
new BinaryServerFormatterSinkProvider());
ChannelServices.RegisterChannel(channel);

注册Http通道:

IDictionary httpProp = new Hashtable();
httpProp["name"] = "http8080";
httpProp["port"] = 8080;
IChannel channel = new HttpChannel(httpProp,
new SoapClientFormatterSinkProvider(),
new SoapServerFormatterSinkProvider());
ChannelServices.RegisterChannel(channel);

问题到这里算解决了,但是,我觉得有必要研究清楚最开始我们的代码出了什么问题。

TcpChannel channel = new TcpChannel(8080);
ChannelServices.RegisterChannel(channel);

这样的注册方式只改变端口参数为什么无法实现多通道呢?原来 new TcpChannel(8080)方式创建的TcpChannel实例的Name属性默认为"tcp",而以new HttpChannel(8080)方式创建的HttpChannel实例其Name属性为"http",那么两个通道名称都是"tcp"这样就违反了通道名作为区别通道标识的原则,当然就失败了。清楚了,文章完。

篇外: 有句话说的好:"细节决定成败!" 细节其实往往是学习中最难掌握的,如果说高手和菜鸟的区别主要在编程思想的话,那么可以这么说,高手和菜鸟在编程技术上的区别主要是在细节的掌握上,掌握细节,那么你也算个“小高手”。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: