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

在微风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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值