Peer.cs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. using StackExchange.Redis;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Net.Sockets;
  6. using System.Threading.Channels;
  7. using System.Threading.Tasks;
  8. using ProtoDataBuff;
  9. using pb = global::Google.Protobuf;
  10. namespace BossServer.server
  11. {
  12. /// <summary>
  13. /// 客户端状态
  14. /// </summary>
  15. enum ClientState
  16. {
  17. /// <summary>
  18. /// 已连接,未登录
  19. /// </summary>
  20. Connected,
  21. /// <summary>
  22. /// 已登录
  23. /// </summary>
  24. Authenticated,
  25. /// <summary>
  26. /// 已离开
  27. /// </summary>
  28. Leaved
  29. }
  30. /// <summary>
  31. /// 一个连接对象的抽象,代表一个远端的对象
  32. /// </summary>
  33. class Peer
  34. {
  35. /// <summary>
  36. /// 玩家属性字段
  37. /// </summary>
  38. public Dictionary<string, object> Properties = new();
  39. /// <summary>
  40. /// 客户端状态字段
  41. /// </summary>
  42. public ClientState CurrentState = ClientState.Connected;
  43. /// <summary>
  44. /// peer的唯一Id
  45. /// </summary>
  46. public readonly int Id;
  47. /// <summary>
  48. /// socket连接
  49. /// </summary>
  50. public readonly Socket Sock;
  51. public string UID
  52. {
  53. get
  54. {
  55. if (Properties.TryGetValue(PropertyName.Uid, out var uid))
  56. {
  57. return uid.ToString();
  58. }
  59. return "";
  60. }
  61. }
  62. public int zoneid
  63. {
  64. get
  65. {
  66. if (Properties.TryGetValue(PropertyName.Zoneid, out var zoneid))
  67. {
  68. return Convert.ToInt32(zoneid);
  69. }
  70. return 1;
  71. }
  72. }
  73. public int bossId;
  74. /// <summary>
  75. /// 所属boss 的关键key
  76. /// </summary>
  77. public string BossKey => $"{zoneid}-{bossId}";
  78. /// <summary>
  79. /// 线程安全的peer计数器
  80. /// </summary>
  81. private volatile static int _UniqPeerId = 0;
  82. /// <summary>
  83. /// 构造函数
  84. /// </summary>
  85. /// <param name="sock"></param>
  86. public Peer(Socket sock)
  87. {
  88. this.Sock = sock;
  89. Sock.ReceiveTimeout = 1500; // 接收等待超时时间设为1.5秒
  90. Id = _UniqPeerId++;
  91. var t = Task.Run(() => recv(Sock)); // 新建接收线程
  92. var tcs = Task.Run(WriteToClient); // 向客户端发送消息线程
  93. }
  94. public void Close()
  95. {
  96. this.CurrentState = ClientState.Leaved; // 关闭接收窗口
  97. Room.Instance.RemovePeer(this); // 从房间中移除自己
  98. //SaveDamage();
  99. this.sendDataBuffer.Reader.Completion
  100. .ContinueWith(t =>
  101. Task.Delay(5000).ContinueWith(t1 => Sock.Close())
  102. ); // 延迟5秒关闭套接字
  103. }
  104. public void AddDamage(int damage)
  105. {
  106. if (Properties.ContainsKey(PropertyName.TotalDamage))
  107. {
  108. var totalDamage = Convert.ToInt32(Properties[PropertyName.TotalDamage]);
  109. Properties[PropertyName.TotalDamage] = damage + totalDamage;
  110. }
  111. else
  112. {
  113. Properties.Add(PropertyName.TotalDamage, damage);
  114. }
  115. SaveDamage(damage);
  116. }
  117. void SaveDamage(int damage)
  118. {
  119. try
  120. {
  121. var rdb = Redis.Ins.GetDatabase(0);
  122. if (Properties.TryGetValue(PropertyName.Name, out var name)
  123. && Properties.TryGetValue(PropertyName.Zoneid, out var zoneid))
  124. {
  125. var roomName = Room.Instance.Name ?? "Room";
  126. var redis_key = MemKey_Game.BossFight_Damage_byDateHour_zset(Convert.ToInt32(zoneid), bossId, roomName);
  127. var who = UID + "__" + name.ToString();
  128. rdb.SortedSetIncrement(redis_key, who, damage);
  129. }
  130. else
  131. {
  132. Console.WriteLine("uid/zoneid 为空.");
  133. }
  134. }
  135. catch (RedisTimeoutException te)
  136. {
  137. Console.WriteLine("redis操作超时");
  138. }
  139. }
  140. /// <summary>
  141. /// 向客户端发送事件
  142. /// </summary>
  143. public void SendEvent(eProtocalCommand msgType, pb::IMessage msg)
  144. {
  145. SendToClient(msgType, msg);
  146. }
  147. /// <summary>
  148. /// 向客户端发送消息
  149. /// </summary>
  150. /// <param name="msgType"></param>
  151. /// <param name="msg"></param>
  152. void SendToClient(eProtocalCommand msgType, pb::IMessage msg)
  153. {
  154. using var ms = new MemoryStream();
  155. using var os = new pb::CodedOutputStream(ms);
  156. msg.WriteTo(os);
  157. os.Flush();
  158. ms.Seek(0, SeekOrigin.Begin);
  159. var sdata = sSocketData.FromBytes(msgType, ms.ToArray());
  160. sendDataBuffer.Writer.WriteAsync(sdata).AsTask().Wait();
  161. }
  162. /// <summary>
  163. /// 向客户端写入消息
  164. /// </summary>
  165. async void WriteToClient()
  166. {
  167. while (true)
  168. {
  169. try
  170. {
  171. var msg = await sendDataBuffer.Reader.ReadAsync();
  172. await Sock.SendAsync(new ArraySegment<byte>(msg.ToBytes()), SocketFlags.None);
  173. }
  174. catch (Exception)
  175. {
  176. break;
  177. }
  178. }
  179. Close();
  180. }
  181. /// <summary>
  182. /// 发送buffer
  183. /// </summary>
  184. private Channel<sSocketData> sendDataBuffer = Channel.CreateUnbounded<sSocketData>();
  185. /// <summary>
  186. /// 接收客户端发来的信息,客户端套接字对象
  187. /// </summary>
  188. /// <param name="socketclientpara"></param>
  189. async void recv(Socket socketServer)
  190. {
  191. var _databuffer = new DataBuffer();
  192. byte[] arrServerRecMsg = new byte[4096]; // 创建一个内存缓冲区,其大小为4k字节
  193. while (true)
  194. {
  195. try
  196. {
  197. var length = await socketServer.ReceiveAsync(new ArraySegment<byte>(arrServerRecMsg), SocketFlags.None); // 将接收到的信息存入到内存缓冲区,并返回其字节数组的长度
  198. if (length <= 0 || CurrentState == ClientState.Leaved) // 视为客户端已经close连接
  199. {
  200. break;
  201. }
  202. _databuffer.AddBuffer(arrServerRecMsg, length); //将收到的数据添加到缓存器中
  203. while (_databuffer.GetData(out sSocketData _socketData)) //取出一条完整数据
  204. {
  205. await Room.Instance.MsgChannel.Writer.WriteAsync(new KeyValuePair<int, sSocketData>(this.Id, _socketData)); // 放入channel
  206. }
  207. Array.Clear(arrServerRecMsg, 0, length);
  208. }
  209. catch (SocketException e)
  210. {
  211. if (e.ErrorCode == 10060) // 超时的时候错误号码是10060
  212. {
  213. continue; // 继续等待
  214. }
  215. break;
  216. }
  217. catch (Exception)
  218. {
  219. break;
  220. }
  221. }
  222. Close(); // 关闭
  223. }
  224. }
  225. }