目标:实现一个简单的聊天室。本文实现的聊天室仅出于演示ICE的多播功能,即由一个Client发送的消息,广播至注册的其他Client上。以后的系列文章,将逐步完善这个例子,使其成为一个现实意义上可用的聊天室软件。
[@more@]
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("请输入用户名:rn");
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("请输入聊天内容:rn");
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
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/7176288/viewspace-913916/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/7176288/viewspace-913916/