Program_MultiDup.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. using System;
  2. using System.IO;
  3. using System.Text;
  4. using System.Threading;
  5. using System.Threading.Tasks;
  6. using System.Threading.Channels;
  7. using System.Linq;
  8. using System.Net.Http;
  9. using System.Collections.Generic;
  10. using Newtonsoft.Json;
  11. using Newtonsoft.Json.Linq;
  12. using System.Net;
  13. using System.Net.Sockets;
  14. using System.Diagnostics;
  15. using ProtoDataBuff;
  16. using MultiDup;
  17. using pb = global::Google.Protobuf;
  18. namespace clientTest.multiDup
  19. {
  20. class Program
  21. {
  22. static readonly Random r = new Random();
  23. /// <summary>
  24. /// 消息分发
  25. /// </summary>
  26. static private Dictionary<eProtocalCommand, Action<sSocketData>> callbacks = new Dictionary<eProtocalCommand, Action<sSocketData>>();
  27. static void Main(string[] args)
  28. {
  29. callbacks.Add(eProtocalCommand.ScMdGetRoomList, On_update);
  30. callbacks.Add(eProtocalCommand.ScMdEnterRoom, On_enter);
  31. callbacks.Add(eProtocalCommand.ScMdBeginDup, On_begin);
  32. callbacks.Add(eProtocalCommand.ScMdLeaveRoom, On_GameOver);
  33. callbacks.Add(eProtocalCommand.ScMdCreateRoom, On_CreateRoom);
  34. var n = 1;
  35. var list = new Task[n];
  36. for (int i = 0; i < n; i++)
  37. {
  38. list[i] = Task.Run(async () => await send());
  39. }
  40. Task.Run(Dispatch);
  41. Task.WaitAll(list);
  42. }
  43. #region 收到消息处理
  44. /// <summary>
  45. /// 更新房间列表
  46. /// </summary>
  47. static void On_update(sSocketData data)
  48. {
  49. Console.WriteLine("最新房间列表: {}");
  50. }
  51. /// <summary>
  52. /// 客户端进入房间
  53. /// </summary>
  54. static void On_CreateRoom(sSocketData data)
  55. {
  56. Console.WriteLine("xxx创建了房间.");
  57. }
  58. /// <summary>
  59. /// 客户端进入房间
  60. /// </summary>
  61. static void On_begin(sSocketData data)
  62. {
  63. Console.WriteLine("xxx开始了游戏.");
  64. }
  65. /// <summary>
  66. /// 客户端进入房间
  67. /// </summary>
  68. static void On_enter(sSocketData data)
  69. {
  70. Console.WriteLine("xx进入了房间.");
  71. }
  72. /// <summary>
  73. /// 处理客户端上报伤害请求
  74. /// </summary>
  75. static void On_GameOver(sSocketData data)
  76. {
  77. Console.WriteLine("xx已离开房间! ");
  78. Task.Delay(3000).ContinueWith(t => Environment.Exit(0));
  79. }
  80. #endregion
  81. static async Task send()
  82. {
  83. var port = 6004;
  84. var endPoint = new IPEndPoint(IPAddress.Parse("192.168.10.17"), port);
  85. //var endPoint = new IPEndPoint(IPAddress.Loopback, port);
  86. //var endPoint = new IPEndPoint(IPAddress.Parse("115.159.121.129"), port);
  87. using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
  88. {
  89. try
  90. {
  91. await client.ConnectAsync(endPoint);
  92. }
  93. catch (Exception ee)
  94. {
  95. Debug.WriteLine(ee.Message);
  96. }
  97. var t = Task.Run(() => recv(client)); // 开启recv监听协程
  98. try
  99. {
  100. // 连上来之后, 创建房间, 开始游戏, 退出房间
  101. CreateRoom(client).Wait();
  102. Thread.Sleep(r.Next(1000, 3000));
  103. await BeginGame(client);
  104. Thread.Sleep(r.Next(1000, 3000));
  105. await LeaveGame(client);
  106. Thread.Sleep(r.Next(1000, 3000));
  107. Console.ReadKey();
  108. }
  109. catch (Exception e)
  110. {
  111. client.Close();
  112. }
  113. finally
  114. {
  115. client.Close();
  116. }
  117. }
  118. }
  119. /// <summary>
  120. /// 创建房间
  121. /// </summary>
  122. /// <param name="Sock"></param>
  123. /// <returns></returns>
  124. async static Task CreateRoom(Socket Sock)
  125. {
  126. try
  127. {
  128. var msg = new CS_MD_CreateRoom() { };
  129. var data = SocketDataToBytes(BytesToSocketData(eProtocalCommand.CsMdCreateRoom, IMsg2Bytes(msg)));
  130. await Sock.SendAsync(new ArraySegment<byte>(data), SocketFlags.None);
  131. }
  132. catch (Exception e)
  133. {
  134. Sock.Close();
  135. }
  136. }
  137. /// <summary>
  138. /// 开始游戏
  139. /// </summary>
  140. /// <param name="sock"></param>
  141. /// <returns></returns>
  142. async static Task BeginGame(Socket sock)
  143. {
  144. var msg = new CS_MD_BeginDup() { };
  145. var data = SocketDataToBytes(BytesToSocketData(eProtocalCommand.CsMdBeginDup, IMsg2Bytes(msg)));
  146. await sock.SendAsync(new ArraySegment<byte>(data), SocketFlags.None);
  147. }
  148. /// <summary>
  149. /// 离开游戏
  150. /// </summary>
  151. /// <param name="sock"></param>
  152. /// <returns></returns>
  153. async static Task LeaveGame(Socket sock)
  154. {
  155. var msg = new CS_MD_LeaveRoom() { };
  156. var data = SocketDataToBytes(BytesToSocketData(eProtocalCommand.CsMdLeaveRoom, IMsg2Bytes(msg)));
  157. await sock.SendAsync(new ArraySegment<byte>(data), SocketFlags.None);
  158. }
  159. #region 消息收发
  160. static byte[] IMsg2Bytes(pb::IMessage msg)
  161. {
  162. using var ms = new MemoryStream();
  163. using var goutstream = new pb::CodedOutputStream(ms);
  164. msg.WriteTo(goutstream);
  165. goutstream.Flush();
  166. ms.Seek(0, SeekOrigin.Begin);
  167. return ms.ToArray();
  168. }
  169. static async void Dispatch()
  170. {
  171. while (true)
  172. {
  173. var msg = await recvDataBuffer.Reader.ReadAsync();
  174. if (callbacks.ContainsKey(msg._protocallType))
  175. {
  176. callbacks[msg._protocallType](msg);
  177. }
  178. else
  179. {
  180. // 未找到消息处理逻辑
  181. Console.WriteLine("未识别的消息类型:" + msg._protocallType.ToString());
  182. }
  183. }
  184. Console.WriteLine("dispatch 已退出");
  185. }
  186. /// <summary>
  187. /// 向客户端写入消息
  188. /// </summary>
  189. static async void WriteToserver(Socket Sock)
  190. {
  191. while (true)
  192. {
  193. var msg = await sendDataBuffer.Reader.ReadAsync();
  194. var data = SocketDataToBytes(msg);
  195. await Sock.SendAsync(new ArraySegment<byte>(data), SocketFlags.None);
  196. }
  197. }
  198. /// <summary>
  199. /// 网络结构转数据
  200. /// </summary>
  201. /// <param name="tmpSocketData"></param>
  202. /// <returns></returns>
  203. static private byte[] SocketDataToBytes(sSocketData tmpSocketData)
  204. {
  205. byte[] _tmpBuff = new byte[tmpSocketData._buffLength];
  206. byte[] _tmpBuffLength = BitConverter.GetBytes(tmpSocketData._buffLength);
  207. byte[] _tmpDataLenght = BitConverter.GetBytes((UInt16)tmpSocketData._protocallType);
  208. Array.Copy(_tmpBuffLength, 0, _tmpBuff, 0, Constants.HEAD_DATA_LEN);//缓存总长度
  209. Array.Copy(_tmpDataLenght, 0, _tmpBuff, Constants.HEAD_DATA_LEN, Constants.HEAD_TYPE_LEN);//协议类型
  210. Array.Copy(tmpSocketData._data, 0, _tmpBuff, Constants.HEAD_LEN, tmpSocketData._dataLength);//协议数据
  211. return _tmpBuff;
  212. }
  213. /// <summary>
  214. /// 数据转网络结构
  215. /// </summary>
  216. /// <param name="_protocalType"></param>
  217. /// <param name="_data"></param>
  218. /// <returns></returns>
  219. static private sSocketData BytesToSocketData(eProtocalCommand _protocalType, byte[] _data)
  220. {
  221. sSocketData tmpSocketData = new sSocketData();
  222. tmpSocketData._buffLength = Constants.HEAD_LEN + _data.Length;
  223. tmpSocketData._dataLength = _data.Length;
  224. tmpSocketData._protocallType = _protocalType;
  225. tmpSocketData._data = _data;
  226. return tmpSocketData;
  227. }
  228. /// <summary>
  229. /// 接收buffer
  230. /// </summary>
  231. static private Channel<sSocketData> recvDataBuffer = Channel.CreateUnbounded<sSocketData>();
  232. /// <summary>
  233. /// 发送buffer
  234. /// </summary>
  235. static private Channel<sSocketData> sendDataBuffer = Channel.CreateUnbounded<sSocketData>();
  236. /// <summary>
  237. /// 接收客户端发来的信息,客户端套接字对象
  238. /// </summary>
  239. /// <param name="socketclientpara"></param>
  240. static async void recv(Socket socketServer)
  241. {
  242. socketServer.ReceiveTimeout = 800; // 接收等待超时时间设为800毫秒
  243. var _databuffer = new DataBuffer();
  244. byte[] arrServerRecMsg = new byte[4096]; // 创建一个内存缓冲区,其大小为4k字节
  245. while (true)
  246. {
  247. try
  248. {
  249. var length = await socketServer.ReceiveAsync(new ArraySegment<byte>(arrServerRecMsg), SocketFlags.None); // 将接收到的信息存入到内存缓冲区,并返回其字节数组的长度
  250. if (length <= 0) // 视为客户端已经close连接
  251. {
  252. break;
  253. }
  254. _databuffer.AddBuffer(arrServerRecMsg, length); //将收到的数据添加到缓存器中
  255. while (_databuffer.GetData(out sSocketData _socketData)) //取出一条完整数据
  256. {
  257. Console.WriteLine("recv: " + _socketData._protocallType);
  258. await recvDataBuffer.Writer.WriteAsync(_socketData); // 放入channel
  259. }
  260. Array.Clear(arrServerRecMsg, 0, length);
  261. }
  262. catch (SocketException e)
  263. {
  264. if (e.ErrorCode == 10060) // 超时的时候错误号码是10060
  265. {
  266. continue; // 继续等待
  267. }
  268. break;
  269. }
  270. catch (Exception)
  271. {
  272. break;
  273. }
  274. }
  275. Console.WriteLine("recv 已退出");
  276. socketServer.Close(); // 关闭之前accept出来的和客户端进行通信的套接字
  277. }
  278. #endregion
  279. }
  280. }