目标:实现一个简单的聊天室。本文实现的聊天室仅出于演示ICE的多播功能,即由一个Client发送的消息,广播至注册的其他Client上。以后的系列文章,将逐步完善这个例子,使其成为一个现实意义上可用的聊天室软件。
Slice定义:
module ChatSpaceDef { //回调函数接口,就是客户端传递给服务器,服务器接收到的一个方法代理签名 interface CallBack { void GetInput(string content); }; //在线列表 dictionary<string,CallBack *> CacheMap; //聊天室功能列表 interface ChatSpace { bool Register(string name);//注册 void SetInput(string content);//发送消息 void Unregister();//退出 void SetupCallback(CallBack * cp);//设置回调 }; }; 运行命令:
slice2cs --output-dir generated *.ice
此命令将生成Client和Server都要使用的应用程序骨架ChatSpaceDef.cs文件。要了解该文件的类的所有信息,
请参考Ice用户手册。
定义服务器端
对服务器而言,实现ChatSpaceDisp_抽象基类即可,换言之,需要实现:
bool Register(string name);//注册 void SetInput(string content);//发送消息 void Unregister();//退出 void SetupCallback(CallBack * cp);//设置回调
这4个方法。代码如下:
using System; using System.Collections.Generic; using System.Text; using ChatSpaceDef; namespace ChatSpace { public sealed class ChatSpaceI : ChatSpaceDisp_ { public override bool Register(string name, Ice.Current current__) { Console.WriteLine("验证 {0} 是否被注册了!", name); return !m_cache_map.Contains(name); } public override void SetInput(string content, Ice.Current current__) {
//向其他人广播消息 string user_name = current__.ctx["user_name"]; foreach (string key in m_cache_map.Keys) { if (key == user_name) { continue; } m_cache_map[key].GetInput(content, current__.ctx); } } public override void Unregister(Ice.Current current__) { if (current__.ctx["user_name"] != null) { m_cache_map.Remove(current__.ctx["user_name"]); Console.WriteLine("注销{0}成功", current__.ctx["user_name"]); } } public override void SetupCallback(CallBackPrx cp, Ice.Current current__) { if (current__ != null && current__.ctx["user_name"] != null) { string user_name = current__.ctx["user_name"]; Console.WriteLine("上下文是user_name={0}", user_name); m_cache_map.Add(user_name, cp); } else { throw new Exception("上下文错误!"); } } CacheMap m_cache_map = new CacheMap(); } }
上述代码都非常简单易懂,需要解释的是:Ice.Current表示调用者携带的上下文信息,这是Ice的内部机制,你可以在
方法调用上,通过Context对象携带其他与调用相关的信息,注意,它不是方法调用的参数,它是Client和Server在网络
中网络环境下传递信息的一种载体。
定义Server端配置config.server:
Callback.Server.Endpoints=tcp -p 12345:udp -p 12345 # # Warn about connection exceptions # Ice.Warn.Connections=1 # # Network Tracing # # 0 = no network tracing # 1 = trace connection establishment and closure # 2 = like 1, but more detailed # 3 = like 2, but also trace data transfer # #Ice.Trace.Network=1 # # Protocol Tracing # # 0 = no protocol tracing # 1 = trace protocol messages # #Ice.Trace.Protocol=1 # # Security Tracing # # 0 = no security tracing # 1 = trace messages # #IceSSL.Trace.Security=1
server端的主程序非常简单Server.cs:
using System; using System.Collections.Generic; using System.Text; namespace ChatSpace { public class Server : Ice.Application { public override int run(string[] args) { Ice.ObjectAdapter adapter = communicator().createObjectAdapter("Callback.Server"); adapter.add(new ChatSpaceI(), communicator().stringToIdentity("callback")); adapter.activate(); communicator().waitForShutdown(); return 0; } public static void Main(string[] args) { Server app = new Server(); int status = app.main(args, "config.server"); if (status != 0) { System.Environment.Exit(status); } } } }
定义客户端
对客户端而言,只需要实现回调方法即可了CallBackI.cs。
using System; using System.Collections.Generic; using System.Text; using ChatSpaceDef; namespace Client { public sealed class CallBackI:CallBackDisp_ { public override void GetInput(string content, Ice.Current current__) { System.Console.WriteLine("服务器传递过来的信息:{0} Say:{1}",current__.ctx["user_name"],content); } } }
客户端主程序Client.cs:
using System; using System.Collections.Generic; using System.Text; using ChatSpaceDef; namespace Client { class Client : Ice.Application { static void Main(string[] args) { Client app = new Client(); int status = app.main(args, "config.client"); if (status != 0) { System.Environment.Exit(status); } } public override int run(string[] args) { ChatSpacePrx spacePrx = ChatSpacePrxHelper. checkedCast(communicator().propertyToProxy("Callback.CallbackServer")); if (spacePrx == null) { System.Console.WriteLine("网络配置无效!"); return 1; } System.Console.WriteLine("请输入用户名:\r\n"); string user_name = Console.ReadLine(); if (spacePrx.Register(user_name) == false) { System.Console.WriteLine("该用户名已被注册!"); return 1; } Ice.ObjectAdapter adapter = communicator().createObjectAdapter("Callback.Client"); adapter.add(new CallBackI(), communicator().stringToIdentity("callbackReceiver")); adapter.activate(); CallBackPrx callbackPrx = CallBackPrxHelper.uncheckedCast(adapter.createProxy(communicator().stringToIdentity("callbackReceiver"))); Ice.Context ctx = new Ice.Context(); ctx.Add("user_name", user_name); spacePrx.SetupCallback(callbackPrx,ctx); System.Console.WriteLine("请输入聊天内容:\r\n"); string content = ""; while (content != "X") { content = System.Console.ReadLine(); spacePrx.SetInput(content,ctx); } spacePrx.Unregister(ctx); return 0; } } }
客户端配置文件:
Callback.CallbackServer=callback:tcp -p 12345:udp -p 12345 Callback.Client.Endpoints=tcp:udp # # Warn about connection exceptions # Ice.Warn.Connections=1 # # Network Tracing # # 0 = no network tracing # 1 = trace connection establishment and closure # 2 = like 1, but more detailed # 3 = like 2, but also trace data transfer # #Ice.Trace.Network=1 # # Protocol Tracing # # 0 = no protocol tracing # 1 = trace protocol messages # #Ice.Trace.Protocol=1 # # Security Tracing # # 0 = no security tracing # 1 = trace messages # #IceSSL.Trace.Security=1 至此,一个多播聊天室就此完成。
编译运行:
ICE,SQLite,JasperReport……开源技术讨论群:25935569,欢迎关注开源技术应用的朋友一起交流进步。
项目下载:项目文件 ICEChatSpace
本文转自斯克迪亚博客园博客,原文链接:http://www.cnblogs.com/sgsoft/archive/2007/05/07/738011.html,如需转载请自行联系原作者