Program_Chat.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  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 Chat;
  17. using pb = global::Google.Protobuf;
  18. namespace clientTest.chat
  19. {
  20. public static class TaskWaitingExtensions
  21. {
  22. public static async Task<TResult> WaitAsync<TResult>(this Task<TResult> task, TimeSpan timeout)
  23. {
  24. using (var timeoutCancellationTokenSource = new CancellationTokenSource())
  25. {
  26. var delayTask = Task.Delay(timeout, timeoutCancellationTokenSource.Token);
  27. if (await Task.WhenAny(task, delayTask) == task)
  28. {
  29. timeoutCancellationTokenSource.Cancel();
  30. return await task;
  31. }
  32. throw new TimeoutException("The operation has timed out.");
  33. }
  34. }
  35. public static async Task WaitAsync(this Task task, TimeSpan timeout)
  36. {
  37. using (var timeoutCancellationTokenSource = new CancellationTokenSource())
  38. {
  39. var delayTask = Task.Delay(timeout, timeoutCancellationTokenSource.Token);
  40. if (await Task.WhenAny(task, delayTask) == task)
  41. {
  42. timeoutCancellationTokenSource.Cancel();
  43. return;
  44. }
  45. throw new TimeoutException("The operation has timed out.");
  46. }
  47. }
  48. }
  49. class Program
  50. {
  51. static readonly string[] names = new string[] { "你猜(尼采)", "黑哥儿(黑格尔)", "孟德四舅" };
  52. static readonly string[] texts = new string[] {
  53. "一个人可以失败很多次,但是只要他没有开始责怪旁人,他还不是一个失败者。",
  54. "这个世界既不是有钱人的世界,也不是有权人的世界,它是有心人的世界。",
  55. "伟人之所以伟大,是因为他与别人共处逆境时,别人失去了信心,他却下决心实现自己的目标。",
  56. "世上没有绝望的处境,只有对处境绝望的人。 ",
  57. "时间就像一张网,你撒在哪里,收获就在哪里。",
  58. "心若计较,处处都是怨言;心不计较,时时都是晴天。",
  59. "能使我们感觉快乐的,不是环境,而是态度。",
  60. "学问是用来实践的,不是拿来用嘴说的。",
  61. "自己打败自己是最可悲的失败,自己战胜自己是最可贵的胜利。",
  62. "我们得成功,其实成功有一条很简单的定律:“只要站起来的次数比被击倒的次数多一次就行。",
  63. " 弱者坐待良机,强者创造时机。",
  64. " 没有不会做的事, 只有不想做的事。",
  65. "任何的限制, 都是从自己内心开始的。",
  66. "只要还有明天, 今日就永远是起跑线。",
  67. "既然认准一条道路, 何必去打听要走多久。",
  68. "现在站在什么地方不重要,重要的是你往什么方向移动?",
  69. "如果什么都想要,只会什么都得不到。"
  70. };
  71. static readonly Random r = new Random();
  72. /// <summary>
  73. /// 消息分发
  74. /// </summary>
  75. static private Dictionary<eProtocalCommand, Action<sSocketData>> callbacks = new Dictionary<eProtocalCommand, Action<sSocketData>>();
  76. static void Main(string[] args)
  77. {
  78. callbacks.Add(eProtocalCommand.ScChatNewMsg, On_update);
  79. callbacks.Add(eProtocalCommand.ScChatLogin, On_LoginOver);
  80. var n = 10;
  81. var list = new Task[n];
  82. for (int i = 0; i < n; i++)
  83. {
  84. list[i] = Task.Run(async () => await send());
  85. }
  86. Task.Run(Dispatch);
  87. Task.WaitAll(list);
  88. }
  89. static string ChannelName(ChatChannel c) => c switch
  90. {
  91. ChatChannel.System => "系统",
  92. ChatChannel.World => "世界",
  93. ChatChannel.Guild => "公会",
  94. _ => "x",
  95. };
  96. /// <summary>
  97. /// 处理客户端上报伤害请求
  98. /// </summary>
  99. static void On_update(sSocketData data)
  100. {
  101. var msg = SC_ChatNewMsg.Parser.ParseFrom(data._data);
  102. Console.WriteLine($"[{ChannelName(msg.FromChannel)}]-[{msg.SenderName}] : " + msg.Msg);
  103. }
  104. /// <summary>
  105. /// 处理客户端上报伤害请求
  106. /// </summary>
  107. static void On_LoginOver(sSocketData data)
  108. {
  109. var msg = SC_ChatLogin.Parser.ParseFrom(data._data);
  110. Console.WriteLine("登录结果: " + msg.Code);
  111. //Task.Delay(3000).ContinueWith(t => Environment.Exit(0));
  112. }
  113. static async Task send()
  114. {
  115. var port = 6000;
  116. var endPoint = new IPEndPoint(IPAddress.Parse("192.168.10.17"), port);
  117. //var endPoint = new IPEndPoint(IPAddress.Loopback, port);
  118. //var endPoint = new IPEndPoint(IPAddress.Parse("115.159.121.129"), port);
  119. using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
  120. {
  121. try
  122. {
  123. await client.ConnectAsync(endPoint);
  124. }
  125. catch (Exception ee)
  126. {
  127. Debug.WriteLine(ee.Message);
  128. }
  129. var t = Task.Run(() => recv(client));
  130. await login(client);
  131. var i = 0;
  132. while (i++ < 10)
  133. {
  134. try
  135. {
  136. await sendMsg(client);
  137. Thread.Sleep(r.Next(1000, 1100));
  138. }
  139. catch (Exception e)
  140. {
  141. client.Close();
  142. break;
  143. }
  144. }
  145. }
  146. }
  147. async static Task login(Socket Sock)
  148. {
  149. try
  150. {
  151. var msg = new CS_ChatLogin() { Uid = Guid.NewGuid().ToString(), Zoneid = 1, Name = names[r.Next(0, 3)] + r.Next() };
  152. var data = SocketDataToBytes(BytesToSocketData(eProtocalCommand.CsChatLogin, IMsg2Bytes(msg)));
  153. await Sock.SendAsync(new ArraySegment<byte>(data), SocketFlags.None);
  154. }
  155. catch (Exception e)
  156. {
  157. Sock.Close();
  158. }
  159. }
  160. async static Task sendMsg(Socket sock)
  161. {
  162. var c = (ChatChannel)r.Next(0, 3);
  163. var info = texts[r.Next(0, texts.Length)];
  164. var msg = new CS_ChatSendMsg() { ToChannel = c, Msg = info };
  165. var data = SocketDataToBytes(BytesToSocketData(eProtocalCommand.CsChatSendMsg, IMsg2Bytes(msg)));
  166. await sock.SendAsync(new ArraySegment<byte>(data), SocketFlags.None);
  167. }
  168. static byte[] IMsg2Bytes(pb::IMessage msg)
  169. {
  170. using var ms = new MemoryStream();
  171. using var goutstream = new pb::CodedOutputStream(ms);
  172. msg.WriteTo(goutstream);
  173. goutstream.Flush();
  174. ms.Seek(0, SeekOrigin.Begin);
  175. return ms.ToArray();
  176. }
  177. static async void Dispatch()
  178. {
  179. while (true)
  180. {
  181. var msg = await recvDataBuffer.Reader.ReadAsync();
  182. if (callbacks.ContainsKey(msg._protocallType))
  183. {
  184. callbacks[msg._protocallType](msg);
  185. }
  186. else
  187. {
  188. // 未找到消息处理逻辑
  189. Console.WriteLine("未识别的消息类型:" + msg._protocallType.ToString());
  190. }
  191. }
  192. }
  193. /// <summary>
  194. /// 向客户端写入消息
  195. /// </summary>
  196. static async void WriteToserver(Socket Sock)
  197. {
  198. while (true)
  199. {
  200. var msg = await sendDataBuffer.Reader.ReadAsync();
  201. var data = SocketDataToBytes(msg);
  202. await Sock.SendAsync(new ArraySegment<byte>(data), SocketFlags.None);
  203. }
  204. }
  205. /// <summary>
  206. /// 网络结构转数据
  207. /// </summary>
  208. /// <param name="tmpSocketData"></param>
  209. /// <returns></returns>
  210. static private byte[] SocketDataToBytes(sSocketData tmpSocketData)
  211. {
  212. byte[] _tmpBuff = new byte[tmpSocketData._buffLength];
  213. byte[] _tmpBuffLength = BitConverter.GetBytes(tmpSocketData._buffLength);
  214. byte[] _tmpDataLenght = BitConverter.GetBytes((UInt16)tmpSocketData._protocallType);
  215. Array.Copy(_tmpBuffLength, 0, _tmpBuff, 0, Constants.HEAD_DATA_LEN);//缓存总长度
  216. Array.Copy(_tmpDataLenght, 0, _tmpBuff, Constants.HEAD_DATA_LEN, Constants.HEAD_TYPE_LEN);//协议类型
  217. Array.Copy(tmpSocketData._data, 0, _tmpBuff, Constants.HEAD_LEN, tmpSocketData._dataLength);//协议数据
  218. return _tmpBuff;
  219. }
  220. /// <summary>
  221. /// 数据转网络结构
  222. /// </summary>
  223. /// <param name="_protocalType"></param>
  224. /// <param name="_data"></param>
  225. /// <returns></returns>
  226. static private sSocketData BytesToSocketData(eProtocalCommand _protocalType, byte[] _data)
  227. {
  228. sSocketData tmpSocketData = new sSocketData();
  229. tmpSocketData._buffLength = Constants.HEAD_LEN + _data.Length;
  230. tmpSocketData._dataLength = _data.Length;
  231. tmpSocketData._protocallType = _protocalType;
  232. tmpSocketData._data = _data;
  233. return tmpSocketData;
  234. }
  235. /// <summary>
  236. /// 接收buffer
  237. /// </summary>
  238. static private Channel<sSocketData> recvDataBuffer = Channel.CreateUnbounded<sSocketData>();
  239. /// <summary>
  240. /// 发送buffer
  241. /// </summary>
  242. static private Channel<sSocketData> sendDataBuffer = Channel.CreateUnbounded<sSocketData>();
  243. /// <summary>
  244. /// 接收客户端发来的信息,客户端套接字对象
  245. /// </summary>
  246. /// <param name="socketclientpara"></param>
  247. static async void recv(Socket socketServer)
  248. {
  249. socketServer.ReceiveTimeout = 800; // 接收等待超时时间设为800毫秒
  250. var _databuffer = new DataBuffer();
  251. byte[] arrServerRecMsg = new byte[4096]; // 创建一个内存缓冲区,其大小为4k字节
  252. while (true)
  253. {
  254. try
  255. {
  256. var length = await socketServer.ReceiveAsync(new ArraySegment<byte>(arrServerRecMsg), SocketFlags.None); // 将接收到的信息存入到内存缓冲区,并返回其字节数组的长度
  257. if (length <= 0) // 视为客户端已经close连接
  258. {
  259. break;
  260. }
  261. _databuffer.AddBuffer(arrServerRecMsg, length); //将收到的数据添加到缓存器中
  262. while (_databuffer.GetData(out sSocketData _socketData)) //取出一条完整数据
  263. {
  264. await recvDataBuffer.Writer.WriteAsync(_socketData); // 放入channel
  265. }
  266. Array.Clear(arrServerRecMsg, 0, length);
  267. }
  268. catch (SocketException e)
  269. {
  270. if (e.ErrorCode == 10060) // 超时的时候错误号码是10060
  271. {
  272. continue; // 继续等待
  273. }
  274. break;
  275. }
  276. catch (Exception)
  277. {
  278. break;
  279. }
  280. }
  281. socketServer.Close(); // 关闭之前accept出来的和客户端进行通信的套接字
  282. }
  283. }
  284. }