.net remoting 接口 异步调用 回调 tcp 编码配置

参考了<<.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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值