.Net Remoting 实现简易的控制台命令行聊天室
本套程序由四个主要的对象组成:
1. ChatRoom (ChatRoom.cs): 服务器端真正的提供远程服务的对象,负责以服务器推(push)的方式把 Sender 发来的消息"广播"出去。
2004-12-29 修订,使 Server Side 程序更加健壮!
/*
csc.exe ChatRoom.cs /t:library ChatRoom.dll
*/
using System;
using System.Runtime.Remoting;
//[Serializable]
public class ChatRoom : MarshalByRefObject
{
//定义了 1 个名为 "ChatRoomEventHandler 的事件处理委托" 及其参数格式签名
public delegate void ChatRoomEventHandler(string s);
//定义了 3 个 "ChatRoomEventHandler 委托类型" 的事件及远程回调函数
public event ChatRoomEventHandler MessageReceive; //消息接收事件
public event ChatRoomEventHandler Login; //登录事件
public event ChatRoomEventHandler Logoff; //退出事件
//[System.Runtime.Remoting.Messaging.OneWay]
public void OnMessageReceive(string Message)
{
if (MessageReceive != null)
{
//触发 Receiver 客户端 MessageReceive 事件,广播所有消息
RaiseEvents(ref MessageReceive,ref Message);
//MessageReceive(Message);
}
Console.WriteLine("Server: " + Message); //服务器消息监视
}
//[System.Runtime.Remoting.Messaging.OneWay]
public void OnLogin(string User)
{
string s = "System say: " + User + " Login!";
if (Login != null)
{
//触发 Receiver 客户端 Login 事件,广播 "登录" 消息
RaiseEvents(ref Login,ref s);
//Login("System say: " + User + " Login!");
}
Console.WriteLine("Server: " + s);
}
//[System.Runtime.Remoting.Messaging.OneWay]
public void OnLogoff(string User)
{
string s = "System say: " + User + " Logoff!";
if (Logoff != null)
{
//触发 Receiver 客户端 Logoff 事件,广播 "退出" 消息
//Logoff("System say: " + User + " Logoff!");
RaiseEvents(ref Logoff,ref s);
}
Console.WriteLine("Server: " + s);
}
public override object InitializeLifetimeService()
{
return null;
}
//参阅 Ingo Rammer《Advanced .NET Remoting》
public void RaiseEvents(ref ChatRoomEventHandler e,ref string Message)
{
ChatRoomEventHandler creh = null;
int i = 1;
Delegate[] D = e.GetInvocationList();
foreach (Delegate d in D)
{
try
{
creh = (ChatRoomEventHandler) d;
creh(Message);
}
catch
{
Message = "第 " + i.ToString() + " 个订阅者发生错误,系统取消其事件订阅!";
e -= creh;
}
i ++;
}
}
}
2. Server: 服务器。远程服务对象的宿主程序而已。
/*
csc.exe Server.cs
*/
using System;
using System.Runtime.Remoting;
class Server
{
public static void Main(string[] Args)
{
RemotingConfiguration.Configure("s.config");
Console.WriteLine("Server .... , Press Enter key to exit.");
Console.ReadLine();
}
}
下面是 Server 的配置文件 (s.config):
<configuration>
<system.runtime.remoting>
<application>
<service>
<wellknown mode="Singleton" type="ChatRoom,ChatRoom" objectUri="ChatRoomURL" />
</service>
<channels>
<channel ref="http" port="8080">
<serverProviders>
<provider ref="wsdl" />
<formatter ref="soap" typeFilterLevel="Full" />
<formatter ref="binary" typeFilterLevel="Full" />
</serverProviders>
<clientProviders>
<formatter ref="binary" />
</clientProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>
3. Sender (Sender.cs): 客户端消息发送器对象,负责把"广播"的消息发送到远程服务对象。
/*
csc.exe /r:ChatRoom.dll Sender.cs
*/
using System;
using System.Timers;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
class Sender
{
ChatRoom x;
public static void Main(string[] Args)
{
Sender y = new Sender();
y.Run();
}
string User;
public void Run()
{
Console.WriteLine("Messages Sender ... ,Press 'q' to exit Chatting.");
//以配置方式获取远程服务对象实例
//RemotingConfiguration.Configure("c.config");
//x = new ChatRoom();
//以编程方式获取远程服务对象实例
System.Runtime.Remoting.Channels.ChannelServices.RegisterChannel(new System.Runtime.Remoting.Channels.Http.HttpChannel());
x = (ChatRoom) System.Activator.GetObject(typeof(ChatRoom),"http://server:8080/ChatRoomURL");
//先登录
Console.WriteLine("make a name then Login Please:");
User = Console.ReadLine();
//调用此远程方法,通知服务器触发 Receiver 客户端 Login 事件,广播 "登录" 消息
x.OnLogin(User);
Console.WriteLine("welcome " + User + ",Send your Message Please:");
string s; //存储键入的消息文字
while ((s=Console.ReadLine()) != "q") //如果键入 q 退出循环
{
//调用此远程方法,通知服务器触发 Receiver 客户端 MessageReceive 事件,广播你所键入的消息
x.OnMessageReceive(User + " say: " + s);
}
//调用此远程方法,通知服务器触发 Receiver 客户端 Logoff 事件,广播 "退出" 消息
x.OnLogoff(User);
Console.WriteLine("bye bye " + User);
}
}
4. Receiver (Receiver.cs): 客户端消息接收器对象,负责"自动"接收远程服务对象从 Sender 接收并转发"广播"的所有消息。
/*
csc.exe /r:ChatRoom.dll Receiver.cs
*/
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
//Receiver 对象必须要继承 MarshalByRefObject,由于相对于服务器, Receiver 对象 也要为其提供远程服务。
class Receiver : MarshalByRefObject
{
ChatRoom x;
public static void Main()
{
Receiver y = new Receiver();
y.Run();
}
public void Run()
{
RemotingConfiguration.Configure("c.config"); //相当于后期运行时绑定
x = new ChatRoom();
//向远程服务对象"注册"本地回调函数 this.Message_Receive1
x.MessageReceive += new ChatRoom.ChatRoomEventHandler(this.Message_Receive1);
//Login Logoff 与 MessageReceive 签名一样
x.Login += new ChatRoom.ChatRoomEventHandler(this.Message_Receive1);
x.Logoff += new ChatRoom.ChatRoomEventHandler(this.Message_Receive1);
Console.WriteLine("Messages Receiver ... ,Press Enter key to exit.");
Console.ReadLine(); //退出关闭接收器
//千万不要忘记结束时取消委托关系
x.MessageReceive -= new ChatRoom.ChatRoomEventHandler(this.Message_Receive1);
x.Login -= new ChatRoom.ChatRoomEventHandler(this.Message_Receive1);
x.Logoff -= new ChatRoom.ChatRoomEventHandler(this.Message_Receive1);
}
//这个就是被服务器端远程回调的函数
public void Message_Receive1(string s)
{
Console.WriteLine(s);//在本地显示接收的广播消息
}
public override object InitializeLifetimeService()
{
return null;
}
}
下面是 Sender 和 Receiver 的配置文件 (c.config):
<configuration>
<system.runtime.remoting>
<application>
<client>
<wellknown type="ChatRoom,ChatRoom" url="http://server:8080/ChatRoomURL" />
</client>
<channels>
<channel ref="http" port="0" />
</channels>
</application>
</system.runtime.remoting>
</configuration>
编译:
csc /t:library chatroom.cs
csc /r:chatroom.dll server.cs
csc /r:chatroom.dll sender.cs
csc /r:chatroom.dll receiver.cs
用法:
运行顺序:
1.先运行 服务器端:
Server.exe
2.再运行 客户端:
Sender.exe 用于登录、发消息、退出
Receiver.exe 仅用与接收并显示消息
注意: 不要通过关闭命令行控制台窗口退出程序!
Server.exe : Press "Enter" key to exit!
Sender.exe : Press "q" key to exit!
Receiver.exe : Press "Enter" key to exit!