http://msdn.microsoft.com/library/chs/cpguide/html/cpconevents.asp
我们先来改造一下上次的程序,为上次的主线程方法添加事件,能不断的引发事件来汇报处理的进度:
public class myeventargs
{
private int _rate;
public int rate
{
get
{
return _rate;
}
}
public myeventargs(int rate)
{
this._rate=rate;
}
}
public class myobject
{
public delegate void myeventhandler(object sender,myeventargs e);
public event myeventhandler myevent;
public void alongtimemethod(int time)
{
console.writeline("主线程方法开始");
for(int i=0;i<100;i++)
{
system.threading.thread.sleep(time);
onmyevent(new myeventargs(i));
}
console.writeline("主线程方法结束");
}
protected void onmyevent(myeventargs e)
{
if (myevent!=null)
{
myevent(this,e);
}
}
}
{
private int _rate;
public int rate
{
get
{
return _rate;
}
}
public myeventargs(int rate)
{
this._rate=rate;
}
}
public class myobject
{
public delegate void myeventhandler(object sender,myeventargs e);
public event myeventhandler myevent;
public void alongtimemethod(int time)
{
console.writeline("主线程方法开始");
for(int i=0;i<100;i++)
{
system.threading.thread.sleep(time);
onmyevent(new myeventargs(i));
}
console.writeline("主线程方法结束");
}
protected void onmyevent(myeventargs e)
{
if (myevent!=null)
{
myevent(this,e);
}
}
}
再来为事件添加处理程序:
class myclient
{
[stathread]
static void main(string[] args)
{
datetime dt=datetime.now;
myobject obj=new myobject();
obj.myevent+=new myobject.myeventhandler(obj_myevent);
obj.alongtimemethod(50);
console.writeline("用了"+((timespan)(datetime.now-dt)).totalseconds+"秒");
console.readline();
}
public static void obj_myevent(object sender,myeventargs e)
{
console.writeline("主线程方法完成了"+e.rate+"%");
}
}
{
[stathread]
static void main(string[] args)
{
datetime dt=datetime.now;
myobject obj=new myobject();
obj.myevent+=new myobject.myeventhandler(obj_myevent);
obj.alongtimemethod(50);
console.writeline("用了"+((timespan)(datetime.now-dt)).totalseconds+"秒");
console.readline();
}
public static void obj_myevent(object sender,myeventargs e)
{
console.writeline("主线程方法完成了"+e.rate+"%");
}
}
运行程序可以看到:
这个是本地的,远程对象的事件也这么简单吗?其实没有想象的简单,因为对象是在远程的,服务端的事件客户端怎么捕捉?应该说远程对象的事件可以分成客户端触发-》服务器应答,服务端触发-》客户端应答和客户端触发-》客户端应答,第一种就很简单了,后面2种都需要有一个中间件。下面我们来要为程对象同样来添加一个进度机制,首先来建立我们的远程对象:
[serializable]
public class myeventargs:eventargs
{
private int _rate;
private string _ip;
public int rate
{
get
{
return _rate;
}
}
public string ip
{
get
{
return _ip;
}
}
public myeventargs(int rate,string ip)
{
this._rate=rate;
this._ip=ip;
}
}
public class myobject:marshalbyrefobject
{
public delegate void myeventhandler(object sender,myeventargs e);
public event myeventhandler myevent;
public int alongtimemethod(int a,int b,int time,string ip)
{
console.writeline("异步方法开始");
for(int i=0;i<10;i++)
{
system.threading.thread.sleep(time);
onmyevent(new myeventargs(i,ip));
}
console.writeline("异步方法结束");
return a+b;
}
protected void onmyevent(myeventargs e)
{
if (myevent!=null)
{
myevent(this,e);
}
}
}
public class myeventargs:eventargs
{
private int _rate;
private string _ip;
public int rate
{
get
{
return _rate;
}
}
public string ip
{
get
{
return _ip;
}
}
public myeventargs(int rate,string ip)
{
this._rate=rate;
this._ip=ip;
}
}
public class myobject:marshalbyrefobject
{
public delegate void myeventhandler(object sender,myeventargs e);
public event myeventhandler myevent;
public int alongtimemethod(int a,int b,int time,string ip)
{
console.writeline("异步方法开始");
for(int i=0;i<10;i++)
{
system.threading.thread.sleep(time);
onmyevent(new myeventargs(i,ip));
}
console.writeline("异步方法结束");
return a+b;
}
protected void onmyevent(myeventargs e)
{
if (myevent!=null)
{
myevent(this,e);
}
}
}
为了调试方便,服务器端和客户端这次都用程序实现,下面是服务器端:
using system;
using system.collections;
using system.runtime.remoting;
using system.runtime.remoting.channels;
using system.runtime.remoting.channels.tcp;
using system.runtime.serialization.formatters;
namespace remoteserver
{
class myserver
{
[stathread]
static void main(string[] args)
{
remotingconfiguration.registerwellknownservicetype(typeof(remoteobject.myobject),"remoteobject.myobject",wellknownobjectmode.singleton);
binaryserverformattersinkprovider serverprovider = new binaryserverformattersinkprovider();
binaryclientformattersinkprovider clientprovider = new binaryclientformattersinkprovider();
serverprovider.typefilterlevel = typefilterlevel.full;
idictionary props = new hashtable();
props["port"]=9999;
tcpchannel channel = new tcpchannel(props,clientprovider,serverprovider);
channelservices.registerchannel(channel);
console.readline();
}
}
}
using system.collections;
using system.runtime.remoting;
using system.runtime.remoting.channels;
using system.runtime.remoting.channels.tcp;
using system.runtime.serialization.formatters;
namespace remoteserver
{
class myserver
{
[stathread]
static void main(string[] args)
{
remotingconfiguration.registerwellknownservicetype(typeof(remoteobject.myobject),"remoteobject.myobject",wellknownobjectmode.singleton);
binaryserverformattersinkprovider serverprovider = new binaryserverformattersinkprovider();
binaryclientformattersinkprovider clientprovider = new binaryclientformattersinkprovider();
serverprovider.typefilterlevel = typefilterlevel.full;
idictionary props = new hashtable();
props["port"]=9999;
tcpchannel channel = new tcpchannel(props,clientprovider,serverprovider);
channelservices.registerchannel(channel);
console.readline();
}
}
}
客户端为了简单一点,我去除了前面做测试的本地事件:
using system;
using system.net;
using system.collections;
using system.text;
using system.runtime.remoting;
using system.runtime.remoting.channels;
using system.runtime.remoting.channels.tcp;
using system.runtime.serialization.formatters;
class myclient
{
private delegate int mydelegate(int a,int b,int time,string ip);
private static mydelegate md;
[stathread]
static void main(string[] args)
{
datetime dt=datetime.now;
remotingconfiguration.registerwellknownclienttype(typeof(remoteobject.myobject), "tcp://localhost:9999/remoteobject.myobject");
binaryserverformattersinkprovider serverprovider = new binaryserverformattersinkprovider();
binaryclientformattersinkprovider clientprovider = new binaryclientformattersinkprovider();
serverprovider.typefilterlevel = typefilterlevel.full;
idictionary props=new hashtable();
props["port"]=0;
tcpchannel channel = new tcpchannel(props,clientprovider,serverprovider);
channelservices.registerchannel(channel);
remoteobject.myobject app=new remoteobject.myobject();
app.myevent+=new remoteobject.myobject.myeventhandler(myevent);
md=new mydelegate(app.alongtimemethod);
asynccallback ac=new asynccallback(myclient.callback);
iphostentry iphe=dns.gethostbyname(dns.gethostname());
iasyncresult iar=md.begininvoke(1,2,300,iphe.addresslist[0].tostring(),ac,null);
method();
console.writeline("用了"+((timespan)(datetime.now-dt)).totalseconds+"秒");
channelservices.unregisterchannel(channel);
console.readline();
}
public static void callback(iasyncresult iar)
{
if(iar.iscompleted)
{
console.writeline("结果是"+md.endinvoke(iar));
}
}
public static void myevent(object sender,remoteobject.myeventargs e)
{
console.writeline("来自"+e.ip+"的异步方法完成了"+e.rate*10+"%");
}
public static void method()
{
console.writeline("主线程方法开始");
system.threading.thread.sleep(5000);
console.writeline("主线程方法结束");
}
}
using system.net;
using system.collections;
using system.text;
using system.runtime.remoting;
using system.runtime.remoting.channels;
using system.runtime.remoting.channels.tcp;
using system.runtime.serialization.formatters;
class myclient
{
private delegate int mydelegate(int a,int b,int time,string ip);
private static mydelegate md;
[stathread]
static void main(string[] args)
{
datetime dt=datetime.now;
remotingconfiguration.registerwellknownclienttype(typeof(remoteobject.myobject), "tcp://localhost:9999/remoteobject.myobject");
binaryserverformattersinkprovider serverprovider = new binaryserverformattersinkprovider();
binaryclientformattersinkprovider clientprovider = new binaryclientformattersinkprovider();
serverprovider.typefilterlevel = typefilterlevel.full;
idictionary props=new hashtable();
props["port"]=0;
tcpchannel channel = new tcpchannel(props,clientprovider,serverprovider);
channelservices.registerchannel(channel);
remoteobject.myobject app=new remoteobject.myobject();
app.myevent+=new remoteobject.myobject.myeventhandler(myevent);
md=new mydelegate(app.alongtimemethod);
asynccallback ac=new asynccallback(myclient.callback);
iphostentry iphe=dns.gethostbyname(dns.gethostname());
iasyncresult iar=md.begininvoke(1,2,300,iphe.addresslist[0].tostring(),ac,null);
method();
console.writeline("用了"+((timespan)(datetime.now-dt)).totalseconds+"秒");
channelservices.unregisterchannel(channel);
console.readline();
}
public static void callback(iasyncresult iar)
{
if(iar.iscompleted)
{
console.writeline("结果是"+md.endinvoke(iar));
}
}
public static void myevent(object sender,remoteobject.myeventargs e)
{
console.writeline("来自"+e.ip+"的异步方法完成了"+e.rate*10+"%");
}
public static void method()
{
console.writeline("主线程方法开始");
system.threading.thread.sleep(5000);
console.writeline("主线程方法结束");
}
}
代码看上去不错,可是debug启动后报错:
这就是我前面提到的问题,远程不可能有本地的程序集,也无法触发本地事件。解决办法就是加一个事件中间件,继承marshalbyrefobject:
public class eventclass:marshalbyrefobject
{
public void myevent(object sender,myeventargs e)
{
console.writeline("来自"+e.ip+"的异步方法完成了"+e.rate*10+"%");
}
}
{
public void myevent(object sender,myeventargs e)
{
console.writeline("来自"+e.ip+"的异步方法完成了"+e.rate*10+"%");
}
}
然后来修改一下客户端:
把app.myevent+=new remoteobject.myobject.myeventhandler(myevent);修改为
remoteobject.eventclass ec=new remoteobject.eventclass();
app.myevent+=new remoteobject.myobject.myeventhandler(ec.myevent);
app.myevent+=new remoteobject.myobject.myeventhandler(ec.myevent);
运行一下程序:
前后两个窗口本别是服务端和客户端的,貌似达到了我们的要求,其实不然,程序有2个漏洞:
1、客户端关闭以后打开新的程序就出错,因为以前的委托链丢失,服务端程序企图触发事件出错。
2、同时打开几个客户端,客户端收到的是所有的进度信息,而不仅仅是自己的,广播性质的消息。
文章整理:站长天空 网址:http://www.z6688.com/
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!




