Program_MultiDup.cs 14 KB

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