本篇完成 4.1 所述聊天系统基本功能部分
先看下使用截图
通过菜单中的 file ,load 登录,需输入名字
主界面左侧为当前在线角色列表
右侧上方为当前所有聊天信息集
右侧下方为聊天信息输入窗口(暂且挂钩广播聊天)
工程结构描述
ChatProtocal 聊天协议
ChatService 服务实现
ChatHost 服务宿主(console 程序)
ChatClient 客户端(winform 程序)
涉及到的类型
IChatService 服务契约
IChatServiceCallback 服务回调契约
User 角色信息体
ChatService 服务实现
UserManager 用户管理
ChaterForm 回调协议实现
关键代码段

聊天协议,需会话状态存储用户信息,开启重入防止死锁


[ServiceContract(Namespace =
"szgamer",

Name =
"ChatService",

SessionMode = SessionMode.Required,

ProtectionLevel = ProtectionLevel.None,

CallbackContract=
typeof(IChatServiceCallback))]
public interface IChatService

{

[OperationContract(Name=
"Enter",IsOneWay=
true)]
void Enter(
string name);

[OperationContract(Name =
"Exit", IsOneWay =
true)]
void Exit();

[OperationContract(Name =
"BroadcastChat", IsOneWay =
true)]
void BroadcastChat(
string content);

[OperationContract(Name =
"PrivateChat", IsOneWay =
true)]
void PrivateChat(
string target,
string content);

}


聊天回调协议

public interface IChatServiceCallback

{

[OperationContract(Name =
"BroadcastChated", IsOneWay =
true)]
void BroadcastChated(User who,
string content);

[OperationContract(Name =
"PrivateChated", IsOneWay =
true)]
void PrivateChated(User who,
string content);

[OperationContract(Name =
"NotifyUserList", IsOneWay =
true)]
void NotifyUserList(IList<User> users);

}


用户信息体,只公开运行时标识和名字给客户端


[DataContract(Namespace =
"szgamer", Name =
"User")]
public class User : IExtensibleDataObject

{

[DataMember(Name =
"Rtid", IsRequired =
true, Order = 0)]
public string Rtid

{

get;

set;

}

[DataMember(Name =
"Name", IsRequired =
true, Order = 1)]
public string Name

{

get;

set;

}

public ExtensionDataObject ExtensionData

{

get;

set;

}

public IChatServiceCallback Callback

{

get;

set;

}

public User(
string rtid,
string name, IChatServiceCallback callback)

{

Rtid = rtid;

Name = name;

Callback = callback;

}

public override string ToString()

{
return string.Format(
"{0}: {1}", Name, Rtid);

}

}


用户管理部分,使用需考虑线程安全

public class UserManager

{

List<User> _UserList =
new List<User>();

public IList<User> UserList

{

get {
return _UserList; }

}

object _SyncRoot =
new object();
public object SyncRoot

{

get {
return _SyncRoot; }

}

public event Action UserListChanged;

void RaiseUserListChanged()

{

var h = UserListChanged;
if (h !=
null)

{

h();

}

}

public void AddUser(User user)

{

_UserList.Add(user);


RaiseUserListChanged();

}

public void Remove(
string user)

{
foreach (var i
in _UserList)

{
if (i.Rtid == user)

{

_UserList.Remove(i);

RaiseUserListChanged();
return;

}

}

}

public bool Contains(
string user)

{
return GetUser(user) !=
null;

}

public User GetUser(
string user)

{
foreach (var i
in _UserList)

{
if (i.Rtid == user)

{
return i;

}

}

return null;

}

}



聊天信息广播

public void BroadcastChat(
string content)

{
lock (_UserManager.SyncRoot)

{

var user = _UserManager.GetUser(SessionId);
if (user ==
null)
return;

Console.WriteLine(
string.Format(
"[BroadcastChat] {`0`} {1}", user.ToString(), content));

foreach (var i
in _UserManager.UserList)

{

i.Callback.BroadcastChated(user, content);

}

}

}



tcp 绑定,忽略安全


<bindings>

<netTcpBinding>

<binding name=
"tcpBinding">

<security mode=
"None">

</security>

</binding>

</netTcpBinding>

</bindings>

转载于:https://blog.51cto.com/szgamer/186850