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

来源:互联网 发布:电商行业数据 编辑:程序博客网 时间:2024/06/10 02:52

在微风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");            }        }
复制代码

 

 UserContract契约类
 UserListContract契约类

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

www.networkcomms.cn

www.cnblogs.com/networkcomms

0 0
原创粉丝点击