Program_MultiDup.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  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. var msg = SC_MD_BeginDup.Parser.ParseFrom(data._data);
  64. Console.WriteLine("xxx开始了游戏.");
  65. Console.WriteLine($"正在连接{msg.Battleserver}:{msg.BattleServerPort}");
  66. var endPoint = new IPEndPoint(IPAddress.Parse(msg.Battleserver), msg.BattleServerPort);
  67. //var endPoint = new IPEndPoint(IPAddress.Loopback, port);
  68. //var endPoint = new IPEndPoint(IPAddress.Parse("115.159.121.129"), port);
  69. using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
  70. {
  71. try
  72. {
  73. client.ConnectAsync(endPoint).Wait();
  74. }
  75. catch (Exception ee)
  76. {
  77. Debug.WriteLine(ee.Message);
  78. }
  79. var t = Task.Run(() => recv(client)); // 开启recv监听协程
  80. try
  81. {
  82. BtLogIn(client).Wait();
  83. // 连上来之后, 创建房间, 开始游戏, 退出房间
  84. BtBroadCast(client).Wait();
  85. BtBroadCast(client).Wait();
  86. BtBroadCast(client).Wait();
  87. Console.WriteLine("已经广播3次,exiting.");
  88. }
  89. catch (Exception e)
  90. {
  91. client.Close();
  92. }
  93. finally
  94. {
  95. client.Close();
  96. }
  97. }
  98. }
  99. /// <summary>
  100. /// 客户端进入房间
  101. /// </summary>
  102. static void On_enter(sSocketData data)
  103. {
  104. Console.WriteLine("xx进入了房间.");
  105. }
  106. /// <summary>
  107. /// 处理客户端上报伤害请求
  108. /// </summary>
  109. static void On_GameOver(sSocketData data)
  110. {
  111. Console.WriteLine("xx已离开房间! ");
  112. Task.Delay(3000).ContinueWith(t => Environment.Exit(0));
  113. }
  114. #endregion
  115. async static Task BtLogIn(Socket sock)
  116. {
  117. try
  118. {
  119. var msg = new CS_BT_Login() { Msg = $"来自客户端{Environment.UserDomainName}的登录,{DateTime.Now.ToString()}", Uid = Environment.MachineName, Zoneid = 1 };
  120. var data = SocketDataToBytes(BytesToSocketData(eProtocalCommand.CsBtLogin, IMsg2Bytes(msg)));
  121. await sock.SendAsync(new ArraySegment<byte>(data), SocketFlags.None);
  122. }
  123. catch (Exception e)
  124. {
  125. sock.Close();
  126. }
  127. }
  128. async static Task BtBroadCast(Socket sock)
  129. {
  130. try
  131. {
  132. var msg = new CS_BT_BroadCast() { Msg = $"来自客户端{Environment.UserDomainName}的广播,{DateTime.Now.ToString()}", SenderUid = Environment.MachineName, Zoneid = 1 };
  133. var data = SocketDataToBytes(BytesToSocketData(eProtocalCommand.CsBtBroadCast, IMsg2Bytes(msg)));
  134. await sock.SendAsync(new ArraySegment<byte>(data), SocketFlags.None);
  135. }
  136. catch (Exception e)
  137. {
  138. sock.Close();
  139. }
  140. }
  141. static async Task send()
  142. {
  143. var port = 6004;
  144. var endPoint = new IPEndPoint(IPAddress.Parse("192.168.10.17"), port);
  145. //var endPoint = new IPEndPoint(IPAddress.Loopback, port);
  146. //var endPoint = new IPEndPoint(IPAddress.Parse("115.159.121.129"), port);
  147. using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
  148. {
  149. try
  150. {
  151. await client.ConnectAsync(endPoint);
  152. }
  153. catch (Exception ee)
  154. {
  155. Debug.WriteLine(ee.Message);
  156. }
  157. var t = Task.Run(() => recv(client)); // 开启recv监听协程
  158. try
  159. {
  160. // 连上来之后, 创建房间, 开始游戏, 退出房间
  161. CreateRoom(client).Wait();
  162. Thread.Sleep(r.Next(1000, 3000));
  163. await BeginGame(client);
  164. Thread.Sleep(r.Next(1000, 3000));
  165. await LeaveGame(client);
  166. Thread.Sleep(r.Next(1000, 3000));
  167. Console.ReadKey();
  168. }
  169. catch (Exception e)
  170. {
  171. client.Close();
  172. }
  173. finally
  174. {
  175. client.Close();
  176. }
  177. }
  178. }
  179. /// <summary>
  180. /// 创建房间
  181. /// </summary>
  182. /// <param name="Sock"></param>
  183. /// <returns></returns>
  184. async static Task CreateRoom(Socket Sock)
  185. {
  186. try
  187. {
  188. var msg = new CS_MD_CreateRoom() { Uid = Environment.MachineName, Zoneid = 1 };
  189. var data = SocketDataToBytes(BytesToSocketData(eProtocalCommand.CsMdCreateRoom, IMsg2Bytes(msg)));
  190. await Sock.SendAsync(new ArraySegment<byte>(data), SocketFlags.None);
  191. }
  192. catch (Exception e)
  193. {
  194. Sock.Close();
  195. }
  196. }
  197. /// <summary>
  198. /// 开始游戏
  199. /// </summary>
  200. /// <param name="sock"></param>
  201. /// <returns></returns>
  202. async static Task BeginGame(Socket sock)
  203. {
  204. var msg = new CS_MD_BeginDup() { Uid = Environment.MachineName, Zoneid = 1 };
  205. var data = SocketDataToBytes(BytesToSocketData(eProtocalCommand.CsMdBeginDup, IMsg2Bytes(msg)));
  206. await sock.SendAsync(new ArraySegment<byte>(data), SocketFlags.None);
  207. }
  208. /// <summary>
  209. /// 离开游戏
  210. /// </summary>
  211. /// <param name="sock"></param>
  212. /// <returns></returns>
  213. async static Task LeaveGame(Socket sock)
  214. {
  215. var msg = new CS_MD_LeaveRoom() { Uid = Environment.MachineName, Zoneid = 1 };
  216. var data = SocketDataToBytes(BytesToSocketData(eProtocalCommand.CsMdLeaveRoom, IMsg2Bytes(msg)));
  217. await sock.SendAsync(new ArraySegment<byte>(data), SocketFlags.None);
  218. }
  219. #region 消息收发
  220. static byte[] IMsg2Bytes(pb::IMessage msg)
  221. {
  222. using var ms = new MemoryStream();
  223. using var goutstream = new pb::CodedOutputStream(ms);
  224. msg.WriteTo(goutstream);
  225. goutstream.Flush();
  226. ms.Seek(0, SeekOrigin.Begin);
  227. return ms.ToArray();
  228. }
  229. static async void Dispatch()
  230. {
  231. while (true)
  232. {
  233. var msg = await recvDataBuffer.Reader.ReadAsync();
  234. if (callbacks.ContainsKey(msg._protocallType))
  235. {
  236. callbacks[msg._protocallType](msg);
  237. }
  238. else
  239. {
  240. // 未找到消息处理逻辑
  241. Console.WriteLine("未识别的消息类型:" + msg._protocallType.ToString());
  242. }
  243. }
  244. Console.WriteLine("dispatch 已退出");
  245. }
  246. /// <summary>
  247. /// 向客户端写入消息
  248. /// </summary>
  249. static async void WriteToserver(Socket Sock)
  250. {
  251. while (true)
  252. {
  253. var msg = await sendDataBuffer.Reader.ReadAsync();
  254. var data = SocketDataToBytes(msg);
  255. await Sock.SendAsync(new ArraySegment<byte>(data), SocketFlags.None);
  256. }
  257. }
  258. /// <summary>
  259. /// 网络结构转数据
  260. /// </summary>
  261. /// <param name="tmpSocketData"></param>
  262. /// <returns></returns>
  263. static private byte[] SocketDataToBytes(sSocketData tmpSocketData)
  264. {
  265. byte[] _tmpBuff = new byte[tmpSocketData._buffLength];
  266. byte[] _tmpBuffLength = BitConverter.GetBytes(tmpSocketData._buffLength);
  267. byte[] _tmpDataLenght = BitConverter.GetBytes((UInt16)tmpSocketData._protocallType);
  268. Array.Copy(_tmpBuffLength, 0, _tmpBuff, 0, Constants.HEAD_DATA_LEN);//缓存总长度
  269. Array.Copy(_tmpDataLenght, 0, _tmpBuff, Constants.HEAD_DATA_LEN, Constants.HEAD_TYPE_LEN);//协议类型
  270. Array.Copy(tmpSocketData._data, 0, _tmpBuff, Constants.HEAD_LEN, tmpSocketData._dataLength);//协议数据
  271. return _tmpBuff;
  272. }
  273. /// <summary>
  274. /// 数据转网络结构
  275. /// </summary>
  276. /// <param name="_protocalType"></param>
  277. /// <param name="_data"></param>
  278. /// <returns></returns>
  279. static private sSocketData BytesToSocketData(eProtocalCommand _protocalType, byte[] _data)
  280. {
  281. sSocketData tmpSocketData = new sSocketData();
  282. tmpSocketData._buffLength = Constants.HEAD_LEN + _data.Length;
  283. tmpSocketData._dataLength = _data.Length;
  284. tmpSocketData._protocallType = _protocalType;
  285. tmpSocketData._data = _data;
  286. return tmpSocketData;
  287. }
  288. /// <summary>
  289. /// 接收buffer
  290. /// </summary>
  291. static private Channel<sSocketData> recvDataBuffer = Channel.CreateUnbounded<sSocketData>();
  292. /// <summary>
  293. /// 发送buffer
  294. /// </summary>
  295. static private Channel<sSocketData> sendDataBuffer = Channel.CreateUnbounded<sSocketData>();
  296. /// <summary>
  297. /// 接收客户端发来的信息,客户端套接字对象
  298. /// </summary>
  299. /// <param name="socketclientpara"></param>
  300. static async void recv(Socket socketServer)
  301. {
  302. socketServer.ReceiveTimeout = 800; // 接收等待超时时间设为800毫秒
  303. var _databuffer = new DataBuffer();
  304. byte[] arrServerRecMsg = new byte[4096]; // 创建一个内存缓冲区,其大小为4k字节
  305. while (true)
  306. {
  307. try
  308. {
  309. var length = await socketServer.ReceiveAsync(new ArraySegment<byte>(arrServerRecMsg), SocketFlags.None); // 将接收到的信息存入到内存缓冲区,并返回其字节数组的长度
  310. if (length <= 0) // 视为客户端已经close连接
  311. {
  312. break;
  313. }
  314. _databuffer.AddBuffer(arrServerRecMsg, length); //将收到的数据添加到缓存器中
  315. while (_databuffer.GetData(out sSocketData _socketData)) //取出一条完整数据
  316. {
  317. Console.WriteLine(socketServer.GetHashCode().ToString() + " recv: " + _socketData._protocallType);
  318. await recvDataBuffer.Writer.WriteAsync(_socketData); // 放入channel
  319. }
  320. Array.Clear(arrServerRecMsg, 0, length);
  321. }
  322. catch (SocketException e)
  323. {
  324. if (e.ErrorCode == 10060) // 超时的时候错误号码是10060
  325. {
  326. continue; // 继续等待
  327. }
  328. break;
  329. }
  330. catch (Exception)
  331. {
  332. break;
  333. }
  334. }
  335. Console.WriteLine(socketServer.GetHashCode().ToString() + "recv 已退出");
  336. socketServer.Close(); // 关闭之前accept出来的和客户端进行通信的套接字
  337. }
  338. #endregion
  339. }
  340. }