目标:实现一个简单的聊天室。本文实现的聊天室仅出于演示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("请输入用户名: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
sgsoft 发表于:2007.05.07 17:52 ::分类: (