在微风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