基于Tcp通信的聊天程序微风IM(c#开源) -技术分析(一) 用户管理_.NET_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > .NET > 基于Tcp通信的聊天程序微风IM(c#开源) -技术分析(一) 用户管理

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

 2015/2/13 15:29:14  networkcomms.cn  程序员俱乐部  我要评论(0)
  • 摘要:在微风IM中,如果用户上线了,其他用户的用户列表中,此用户状态更新为上线状态,如果用户下线了,此用户的头像会变成灰色。我们看一下相关的代码:首先是客户端代码(1):UserInfouserInfo=newUserInfo();userInfo.UserID=txtUserID.Text.Trim();userInfo.Password=txtPassword.Text.Trim();//发送契约类给服务器端
  • 标签:程序 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"); } }

 

class="code_img_closed" src="/Upload/Images/2015021315/0015B68B3C38AA5B.gif" alt="" />logs_code_hide('30ae1133-1083-4996-abc7-6dbb6a79580d',event)" src="/Upload/Images/2015021315/2B1B950FA3DF188F.gif" alt="" />
 /// <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

上一篇: 任性求爱季,必胜宅急送带来全“心”情人节! 下一篇: 没有下一篇了!
发表评论
用户名: 匿名