SuperSocket服务器架设(四):我的AppSession连接管理方案(简单版)
1. AppSession连接管理的用处:
a) 服务器向客户端批量推送信息
b) 客户端对客户端的通信
2. 创建客户端管理类MySessionManager,添加静态列表SessionList
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; namespace SuperSocketApp1 { /// <summary> /// MySession对应连接储存类 /// </summary> public static class MySessionManager { public static List<MySession> SessionList = new List<MySession>(); } }
3. SessionList的添加与移除方法1:
a) 在MySession的OnSessionStarted()方法中添加如下代码
MySessionManager.SessionList.Add(this);
b) 在MySession的OnSessionClosed()方法中添加如下代码
MySessionManager.SessionList.Remove(this);
4. SessionList的添加与移除方法2:
a) 在MyServer的OnNewSessionConnected()方法中添加如下代码
MySessionManager.SessionList.Add(session);
b) 在MyServer的OnSessionClosed()方法中添加如下代码
MySessionManager.SessionList.Remove(session);
5. 向客户端推送消息的代码可以自由发挥,比如以自定义命令的方式实现:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using SuperSocket.SocketBase; using SuperSocket.SocketBase.Command; using SuperSocket.SocketBase.Protocol; namespace SuperSocketApp1 { /// <summary> /// 向客户端推送信息 /// </summary> public class PUSH : CommandBase<MySession, StringRequestInfo> { public override void ExecuteCommand(MySession session, StringRequestInfo requestInfo) { /* * 内置命令行协议: * 命令行协议定义了每个请求必须以回车换行结尾 " "。 * 用空格来分割请求的Key和参数 * requestInfo.Body 参数 * requestInfo.Parameters 用空格分隔参数,返回数组 */ foreach (MySession tmp in MySessionManager.SessionList) { tmp.Send(requestInfo.Body); } } } }
6. 客户端间的通信过程为:获取客户端列表,选择客户端并发送消息(这里通过自定义命令实现)
a) 获取客户端列表:创建LIST命令,代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using SuperSocket.SocketBase; using SuperSocket.SocketBase.Command; using SuperSocket.SocketBase.Protocol; namespace SuperSocketApp1 { public class LIST : CommandBase<MySession, StringRequestInfo> { /// <summary> /// 获取客户端列表 /// </summary> /// <param name="session"></param> /// <param name="requestInfo"></param> public override void ExecuteCommand(MySession session, StringRequestInfo requestInfo) { var tmp = ""; //判断clentList中是否有值 if (MySessionManager.SessionList.Count < 1) { tmp = "NoBody."; } else { for (int i = 0; i < MySessionManager.SessionList.Count; i++) { //SessionID为Session的唯一标示 tmp += "Id:" + (i + 1) + ",SessionID:" + MySessionManager.SessionList[i].SessionID; } } session.Send(tmp); } } }
b) 选择客户端并发送消息:创建SEND命令,代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using SuperSocket.SocketBase; using SuperSocket.SocketBase.Command; using SuperSocket.SocketBase.Protocol; namespace SuperSocketApp1 { /// <summary> /// 向客户端推送信息 /// </summary> public class SEND : CommandBase<MySession, StringRequestInfo> { public override void ExecuteCommand(MySession session, StringRequestInfo requestInfo) { /* * 内置命令行协议: * 命令行协议定义了每个请求必须以回车换行结尾 " "。 * 用空格来分割请求的Key和参数 * requestInfo.Body 参数 * requestInfo.Parameters 用空格分隔参数,返回数组 */ //通过参数的个数判断命令类型 if (requestInfo.Parameters.Length < 2) { session.Send("命令格式:send id 信息"); //send 信息 //for (int i = 0; i < Client.clientList.Count; i++) //{ // //取SessionId对应的Session并发送信息 // Client.TestServer.GetAppSessionByID(Client.clientList[i]).Send(requestInfo.Body); //} } else { //send id 信息 //判断id是否合法 if (int.Parse(requestInfo.Parameters[0]) < 1 || int.Parse(requestInfo.Parameters[0]) > MySessionManager.SessionList.Count) { session.Send("id错误。"); } else { int i = int.Parse(requestInfo.Parameters[0]); //取Session并发送信息 MySessionManager.SessionList[i - 1].Send(requestInfo.Parameters[1]); } } } } }
7. 目录结构:
8. MyServer和MySession最终代码:
a) MyServer代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using SuperSocket.SocketBase; using SuperSocket.SocketBase.Config; namespace SuperSocketApp1 { /// <summary> /// 自定义服务器类MyServer,继承AppServer,并传入自定义连接类MySession /// </summary> public class MyServer : AppServer<MySession> { protected override void OnStartup() { base.OnStartup(); Console.WriteLine("服务器已启动"); } /// <summary> /// 输出新连接信息 /// </summary> /// <param name="session"></param> protected override void OnNewSessionConnected(MySession session) { base.OnNewSessionConnected(session); //客户端建立连接,将session加入list MySessionManager.SessionList.Add(session); Console.Write(" " + session.LocalEndPoint.Address.ToString() + ":连接"); } /// <summary> /// 输出断开连接信息 /// </summary> /// <param name="session"></param> /// <param name="reason"></param> protected override void OnSessionClosed(MySession session, CloseReason reason) { base.OnSessionClosed(session, reason); //客户端断开连接,移除session MySessionManager.SessionList.Remove(session); Console.Write(" " + session.LocalEndPoint.Address.ToString() + ":断开连接"); } protected override void OnStopped() { base.OnStopped(); Console.WriteLine("服务器已停止"); } } }
b) MySession代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using SuperSocket; using SuperSocket.Common; using SuperSocket.SocketBase; using SuperSocket.SocketBase.Protocol; namespace SuperSocketApp1 { /// <summary> /// 自定义连接类MySession,继承AppSession,并传入到AppSession /// </summary> public class MySession : AppSession<MySession> { /// <summary> /// 新连接 /// </summary> protected override void OnSessionStarted() { MySessionManager.SessionList.Add(this); Console.WriteLine(this.LocalEndPoint.Address.ToString()); this.Send(" Hello User"); } /// <summary> /// 未知的Command /// </summary> /// <param name="requestInfo"></param> protected override void HandleUnknownRequest(StringRequestInfo requestInfo) { this.Send(" 未知的命令"); } /// <summary> /// 捕捉异常并输出 /// </summary> /// <param name="e"></param> protected override void HandleException(Exception e) { this.Send(" 异常: {0}", e.Message); } /// <summary> /// 连接关闭 /// </summary> /// <param name="reason"></param> protected override void OnSessionClosed(CloseReason reason) { MySessionManager.SessionList.Remove(this); base.OnSessionClosed(reason); } } }
9. 注:AppServer类自带方法GetAllSessions()用于获取所有的AppSession:
a) AppServer中:
foreach (var session in this.GetAllSessions()) { session.Send(now); }
b) 其他地方:
foreach (var session in AppServer.GetAllSessions()) { session.Send(now); }
a) MyServer代码:
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。