参考了<<.net 分布式编程——C# 篇>>
和微软的WebCast,还有其它资料。
只要把远程对象的接口给客户端,不必把远程对象的实现给客户端。
远程对象的实现放在服务器端。
服务器端规定了回调函数的接口,客户端可以实现这个接口,
在异步调用远程对象结束后,调用回调函数,而不是在客户端线程调用回调函数。
=================================================================================
我们先来写一个接口,将这个接口编译成 ClientCallbackInterface.dll
namespace ClientCallbackInterface
{
public interface IClientCallback
{
int ResultCallback(int result);
}
}
服务器端远程对象将使用这个接口来执行回调函数。
=================================================================================
下面写一个类,实现上面的接口,编译成 ClientCallbackLibrary.dll
[先添加对ClientCallbackInterface.dll的引用]
using System.Threading;
using ClientCallbackInterface;
namespace ClientCallbackLibrary
{
[Serializable]//因为这个类要传到远程对象,所以要能序列化的。
public class ClientCallbackSink : MarshalByRefObject, IClientCallback
{
public int ResultCallback(int result)
{
Console.WriteLine("--->>>ResultCallback executing on thread {0}",
Thread.CurrentThread.GetHashCode());
Console.WriteLine("Add result is {0}", result);
Thread.Sleep(3000);//模拟复杂运算
return result * result;//返回一个平方
}
}
}
这个ClientCallbackLibrary.dll只在客户端添加
而服务器端只添加对ClientCallbackInterface.dll的引用
=================================================================================
下面我们来写远程对象的接口,然后编译成: CustomerInterface.dll
先添加对ClientCallbackInterface.dll的引用
using ClientCallbackInterface;
namespace CustomerInterface
{
public interface ICustomerService
{
//int Test();
//ICustomer CreateCustomer(string name);
int Add(int a, int b);
void AsyncAdd(int n1, int n2, IClientCallback callback);
}
}
=================================================================================
现在开始写远程对象了。编译成CustomerLibrary.dll
引用:ClientCallbackInterface.dll 和 CustomerInterface.dll
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Runtime.Remoting.Messaging;
using System.IO;
using CustomerLibrary;
using System.Runtime.Remoting;
using ClientCallbackInterface;
using CustomerInterface;
namespace CustomerLibrary
{
public class CustomerService : MarshalByRefObject, ICustomerService
{
delegate int BinaryOperatorDelegate(int n1, int n2);
public int Add(int a, int b)
{
Console.WriteLine("CustomerService.Add() = " + (a + b));
Thread.Sleep(3000);
return a + b;
}
public void AsyncAdd(int n1, int n2, IClientCallback callback)
{
Console.WriteLine("CustomerLibrary.AsyncAdd() executing on thread {0}",
Thread.CurrentThread.GetHashCode());
BinaryOperatorDelegate binOp;
binOp = new BinaryOperatorDelegate(Add);
binOp.BeginInvoke(n1, n2, new AsyncCallback(DoClientCallback), callback);
}
private void DoClientCallback(IAsyncResult ar)
{
Console.WriteLine("DoClientCallback executing on thread {0}",
Thread.CurrentThread.GetHashCode());
AsyncResult asyncResult = (AsyncResult)ar;
BinaryOperatorDelegate binOp;
binOp = (BinaryOperatorDelegate)asyncResult.AsyncDelegate;
int result = binOp.EndInvoke(ar);
IClientCallback callback = ar.AsyncState as IClientCallback;
if (callback != null)
{
try
{
int tmp = callback.ResultCallback(result);
}
catch (RemotingException e)
{
Console.WriteLine(e.ToString());
}
catch (IOException e)
{
Console.WriteLine(e.ToString());
}
finally
{
}
}
}
public override object InitializeLifetimeService()
{
return null;
}
}
}
=================================================================================
下面写服务器端,引用了ClientCallbackInterface.dll
CustomerInterface.dll
CustomerLibrary.dll
System.Runtime.Remoting.dll
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Remoting.Channels;
using CustomerLibrary;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Serialization.Formatters;
using System.Collections;
namespace CustomerServer
{
class CustomerServerMain
{
static void Main(string[] args)
{
Console.WriteLine("Customer Server initializing...");
BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();
BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider();
serverProvider.TypeFilterLevel = TypeFilterLevel.Full;
IDictionary tcpProps = new Hashtable();
tcpProps["port"] = 13101;
tcpProps["name"] = "server";
TcpChannel channel = new TcpChannel(tcpProps, clientProvider, serverProvider);
ChannelServices.RegisterChannel(channel, true);
ObjRef serverObjRef = RemotingServices.Marshal(new CustomerService(), "ServerObject");//这样就发布了远程对象,是Singleton模式的
Console.WriteLine("Application: " + RemotingConfiguration.ApplicationName);
Console.WriteLine("Waiting for clients. Press 'q' to quit");
string input;
do//服务器端需要一直执行。
{
input = Console.ReadLine();
} while (input != "q");
UnregistrationChannel("server");
}
static private void UnregistrationChannel(string channelName)
{
//获得当前已注册的通道;
IChannel[] channels = ChannelServices.RegisteredChannels;
//关闭指定名为channelName的通道;
foreach (IChannel channel in channels)
{
if (channel.ChannelName == channelName)
{
TcpChannel tcpChannel = (TcpChannel)channel;
//关闭监听
tcpChannel.StopListening(null);
//注销通道
ChannelServices.UnregisterChannel(tcpChannel);
}
}
}
}
}
=================================================================================
最后是客户端了:引用:ClientCallbackInterface.dll
ClientCallbackLibrary.dll
CustomerInterface.dll
System.Runtime.Remoting.dll
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Remoting;
using System.Threading;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Channels;
using System.Runtime.Serialization;
using CustomerInterface;
using ClientCallbackLibrary;
using System.Runtime.Serialization.Formatters;
using System.Collections;
namespace CustomerClient
{
class CustomerClientMain
{
delegate int BinaryOperatorDelegate(int n1, int n2);
static void Main(string[] args)
{
Console.WriteLine("Main executing on thread {0}",
Thread.CurrentThread.GetHashCode());
BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();
BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider();
serverProvider.TypeFilterLevel = TypeFilterLevel.Full;
IDictionary props = new Hashtable();
props["port"] = 0;
props["name"] = "client";
TcpChannel chan = new TcpChannel(props, clientProvider, serverProvider);
ChannelServices.RegisterChannel(chan, true);
ICustomerService custSvc = Activator.GetObject(
typeof(CustomerInterface.ICustomerService),
"tcp://localhost:13101/ServerObject"
) as ICustomerService;
ClientCallbackSink callback = new ClientCallbackSink();
try
{
custSvc.AsyncAdd(15, 2, callback);
}
catch (SerializationException e)
{
Console.WriteLine(e.ToString());
}
finally
{
UnregistrationChannel("client");
}
Console.ReadLine();//服务器端没有异常处理,这里要停留一下。不然在服务器端会出现异常。因为回调函数还没有结束。连接暂时不能断开。
UnregistrationChannel("client");
}
static private void UnregistrationChannel(string channelName)
{
//获得当前已注册的通道;
IChannel[] channels = ChannelServices.RegisteredChannels;
//关闭指定名为channelName的通道;
foreach (IChannel channel in channels)
{
if (channel.ChannelName == channelName)
{
TcpChannel tcpChannel = (TcpChannel)channel;
//关闭监听
tcpChannel.StopListening(null);
//注销通道
ChannelServices.UnregisterChannel(tcpChannel);
}
}
}
}
}
最后,我们先运行服务器,再运行客户端就可以测试了。
服务器端运行:
Customer Server initializing...
Application:
Waiting for clients. Press 'q' to quit
CustomerLibrary.AsyncAdd() executing on thread 4
CustomerService.Add() = 17
DoClientCallback executing on thread 5
客户端运行:
Main executing on thread 1
--->>>ResultCallback executing on thread 5
Add result is 17