您的位置:首页 > 理论基础 > 计算机网络

基于Tcp通信的聊天程序微风IM(c#开源) -技术分析(一) 用户管理

2015-03-03 00:00 921 查看
在微风IM中,如果用户上线了,其他用户的用户列表中,此用户状态更新为上线状态,如果用户下线了,此用户的头像会变成灰色。



我们看一下相关的代码:

首先是客户端代码(1):

UserInfo userInfo = new UserInfo(); userInfo.UserID = txtUserID.Text.Trim(); userInfo.Password = txtPassword.Text.Trim(); //发送契约类给服务器端,并获取返回的结果
UserLoginContract loginContract = newTcpConnection.SendReceiveObject<UserInfo, UserLoginContract>("UserLogin", "ResUserLogin", 8000, userInfo); //如果登陆成功
if (loginContract.Message =="success") { 跳转到主窗口 this.DialogResult = DialogResult.OK; }


服务器端有与登陆相对应的处理方法

注册处理方法:

NetworkComms.AppendGlobalIncomingPacketHandler<UserInfo>("UserLogin", IncomingLoginHandler);


处理方法:

//处理用户登录 networkcomms框架会自动把收到的字节反序列化为对应的UserInfo类型的数据
private void IncomingLoginHandler(PacketHeader header, Connection connection, UserInfo userInfo) { try { //从数据库中验证登录信息
UserLoginContract resContract = DoRcUsers.Login(userInfo.UserID, userInfo.Password);
//把验证的结果返回给客户端 connection.SendObject("ResUserLogin", resContract);

//如果客户端用户成功登陆,我们把此用户加入到用户管理器中 if (resContract.Message == "success") { lock (syncLocker) { //同一账号登陆,先退出已经登陆的客户端
if (userManager.ContainsKey(userInfo.UserID)) { //如果此用户ID已经登陆,找到与此用户ID对应的网络连接,关闭此连接,
                //关闭客户端用户连接,我们采用了一个间接的方式,即给客户端用户发一下让其自动退出的消息,客户端用户接到此消息后,会退出。服务器端的心跳检测机制会把
//客户端退出的连接检查出来,并从系统中删除。

foreach (Connection conn in NetworkComms.GetExistingConnection(userManager[userInfo.UserID], ConnectionType.TCP)) { conn.SendObject("CloseConnection", "msg"); }  //如果用户已经登陆,删除之 userManager.Remove(userInfo.UserID); } //注册新的用户 把新登陆的用户添加到用户管理器
if (!userManager.ContainsKey(userInfo.UserID)) { userManager.Add(userInfo.UserID, connection.ConnectionInfo.NetworkIdentifier); } } //用户上线后,通知其他用户
//这个方法负责通知其他用户,当前用户登陆了,你那边可以把头像点亮了

UserStateNotify(userInfo.UserID, true); } } catch (Exception ex) { LogTools.LogException(ex, "IncomingLoginHandler"); } }


我们来看一下负责通知其他用户的这个方法

// 某客户端用户的状态改变后,通知其他用户
private void UserStateNotify(string userID, bool onLine) { try { //用户状态契约类
UserStateContract userState = new UserStateContract(); userState.UserID = userID; userState.OnLine = onLine; IList<ShortGuid> allUserID; lock (syncLocker) { //获取所有用户字典中的用户ID 用户字典中的用户也就是所有的在线用户
//allUserID 获取的是所有用户的网络ID 每一个客户端连接都对应一个网络ID 用于唯一标识一个网络连接。

allUserID = new List<ShortGuid>(userManager.Values); } //给所有用户发送某用户的在线状态
foreach (ShortGuid netID in allUserID) {
//根据网络ID获取网络连接 List<Connection> result = NetworkComms.GetExistingConnection(netID, ConnectionType.TCP); if (result.Count > 0 && result[0].ConnectionInfo.NetworkIdentifier == netID) {
//给网络连接发送通知,有新的用户上线了,以及新用户的信息,客户端收到此消息后会把用户图标点亮 result[0].SendObject("UserStateNotify", userState); } } } catch (Exception ex) { LogTools.LogException(ex, "MainForm.UserStateNotify"); } }


再来看一下服务器端的用户管理器

//在线用户字典
Dictionary<string, ShortGuid> userManager = new Dictionary<string, ShortGuid>();


<string,ShortGuid> string 用来存放用户ID ,ShortGuid用来存放当前用户网络连接对应的唯一网络ID。(通过此网络ID可以找到相应的Tcp连接,并通过连接发送消息给客户端)。

再回过头来看一下客户端收到某用户上线消息相关的代码:

首先客户端注册用户上线消息

NetworkComms.AppendGlobalIncomingPacketHandler<UserStateContract>("UserStateNotify", IncomingUserStateNotify);


处理方法

private void IncomingUserStateNotify(PacketHeader header, Connection connection, UserStateContract userStateContract) {
//如果是用户上线 if (userStateContract.OnLine) { lock (syncLocker) {
//设定此用户的状态属性,属性更新后,用户状态会跟着更新 Common.GetDicUser(userStateContract.UserID).State = OnlineState.Online; } } else { lock (syncLocker) { Common.GetDicUser(userStateContract.UserID).State = OnlineState.Offline; } } }


接着来讲客户端用户登陆,登陆后,跳转到主界面

在主界面窗口中,获取我的好友列表

public void GetAllMyFriend() { //获取之前先清空用户字典
Common.AllUserDic.Clear(); if (Common.AllUserDic.Count == 0) { //向服务器端发送信息并获取结果 获取的用户信息中包含用户状态
UserListContract userListContract = Common.TcpConn.SendReceiveObject<string, UserListContract>("GetFriends", "ResGetFriends", 5000, Common.UserID); //遍历加载好友
foreach (UserContract user in userListContract.UserList) { //把用户添加到字典中 //根据性别 分别使用不同的图标
if (user.IsMale) { Common.AddDicUser(user.UserID, new User(user.UserID, user.Name, user.Declaring, user.IsMale == true ? UserSex.Male : UserSex.Female, Properties.Resources.q1, "电话", "电子邮件", user.OnLine == true ? OnlineState.Online : OnlineState.Offline)); } else { Common.AddDicUser(user.UserID, new User(user.UserID, user.Name, user.Declaring, user.IsMale == true ? UserSex.Male : UserSex.Female, Properties.Resources.q2, "电话", "电子邮件", user.OnLine == true ? OnlineState.Online : OnlineState.Offline)); } } } }


服务器端对应的处理代码:

首先注册处理方法:

//客户端获取好友列表
NetworkComms.AppendGlobalIncomingPacketHandler<string>("GetFriends", IncomingGetFriends);


处理方法:

//客户端获取某用户的好友列表的服务器端处理方法
private void IncomingGetFriends(PacketHeader header, Connection connection, string userID) { try {
//从数据库获取所有好友 IList<UserContract> userContractList = DoRcUsers.GetAllMyFriends(); UserListContract listContract = new UserListContract(userContractList); lock (syncLocker) {
//遍历服务器上的用户管理器,如果用户在线,则设置用户状态为在线状态 foreach (UserContract theuser in userContractList) { //判断其他好友是否在线
if (userManager.ContainsKey(theuser.UserID)) { theuser.OnLine = true; } } } connection.SendObject<UserListContract>("ResGetFriends", listContract); } catch (Exception ex) { LogTools.LogException(ex, "IncomingGetFriends"); } }






/// <summary>
/// 用户信息契约类 /// </summary>
[ProtoContract] public class UserContract { //用户ID
[ProtoMember(1)] public string UserID { get; set; } //用户名
[ProtoMember(2)] public string Name { get; set; } //用户描述
[ProtoMember(3)] public string Declaring { get; set; } //性别
[ProtoMember(4)] public bool IsMale { get; set; } //初始在线状态
[ProtoMember(5)] public bool OnLine { get; set; } public UserContract() { } public UserContract(string userID, string userName, string underWrite, bool male,bool onLine) { this.UserID = userID; this.Name = userName; this.Declaring = underWrite; this.IsMale = male; this.OnLine = onLine; } }


UserContract契约类





/// <summary>
/// 用户信息列表,比如可以传递我的所有好友信息 /// </summary>
[ProtoContract] public class UserListContract { [ProtoMember(1)] public IList<UserContract> UserList { get; set; } //下面这段代码主要是为了防止列表为空,如果列表为空,不加入下面这段代码,序列化会有问题
[DefaultValue(false), ProtoMember(2)] private bool IsEmptyList { get { return UserList != null && UserList.Count == 0; } set { if (value) { UserList = new List<UserContract>(); } } } public UserListContract() { } public UserListContract(IList<UserContract> userList) { this.UserList = userList; } }


UserListContract契约类

至此,用户登陆基本讲清楚了

www.networkcomms.cn

www.cnblogs.com/networkcomms
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐