WaitingClient.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. //------------------------------------------------------------------------------
  2. // 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
  3. // 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
  4. // CSDN博客:https://blog.csdn.net/qq_40374647
  5. // 哔哩哔哩视频:https://space.bilibili.com/94253567
  6. // Gitee源代码仓库:https://gitee.com/RRQM_Home
  7. // Github源代码仓库:https://github.com/RRQM
  8. // API首页:https://www.yuque.com/rrqm/touchsocket/index
  9. // 交流QQ群:234762506
  10. // 感谢您的下载和使用
  11. //------------------------------------------------------------------------------
  12. //------------------------------------------------------------------------------
  13. using System;
  14. using System.Threading;
  15. using System.Threading.Tasks;
  16. using TouchSocket.Core;
  17. using TouchSocket.Resources;
  18. namespace TouchSocket.Sockets
  19. {
  20. internal class WaitingClient<TClient> : DisposableObject, IWaitingClient<TClient> where TClient : IClient, IDefaultSender, ISender
  21. {
  22. private readonly WaitData<ResponsedData> m_waitData;
  23. private volatile bool breaked;
  24. public WaitingClient(TClient client, WaitingOptions waitingOptions)
  25. {
  26. Client = client ?? throw new ArgumentNullException(nameof(client));
  27. m_waitData = new WaitData<ResponsedData>();
  28. WaitingOptions = waitingOptions;
  29. }
  30. public bool CanSend
  31. {
  32. get
  33. {
  34. if (Client is ITcpClientBase tcpClient)
  35. {
  36. return tcpClient.Online;
  37. }
  38. else if (Client is IUdpSession)
  39. {
  40. return true;
  41. }
  42. else
  43. {
  44. return false;
  45. }
  46. }
  47. }
  48. public TClient Client { get; private set; }
  49. public WaitingOptions WaitingOptions { get; set; }
  50. /// <summary>
  51. /// 发送字节流
  52. /// </summary>
  53. /// <param name="buffer">数据缓存区</param>
  54. /// <param name="offset">偏移</param>
  55. /// <param name="length">长度</param>
  56. /// <param name="timeout">超时时间</param>
  57. /// <param name="token">取消令箭</param>
  58. /// <exception cref="NotConnectedException">客户端没有连接</exception>
  59. /// <exception cref="OverlengthException">发送数据超长</exception>
  60. /// <exception cref="Exception">其他异常</exception>
  61. /// <returns>返回的数据</returns>
  62. public ResponsedData SendThenResponse(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken token = default)
  63. {
  64. lock (this)
  65. {
  66. try
  67. {
  68. breaked = false;
  69. m_waitData.Reset();
  70. if (WaitingOptions.BreakTrigger && this.Client is ITcpClientBase tcpClient)
  71. {
  72. tcpClient.Disconnected += this.OnDisconnected;
  73. }
  74. if (WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter)
  75. {
  76. Client.OnHandleReceivedData += OnHandleReceivedData;
  77. }
  78. else
  79. {
  80. Client.OnHandleRawBuffer += OnHandleRawBuffer;
  81. }
  82. if (WaitingOptions.RemoteIPHost != null && Client is IUdpSession session)
  83. {
  84. if (WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || WaitingOptions.AdapterFilter == AdapterFilter.SendAdapter)
  85. {
  86. session.Send(WaitingOptions.RemoteIPHost.EndPoint, buffer, offset, length);
  87. }
  88. else
  89. {
  90. session.DefaultSend(WaitingOptions.RemoteIPHost.EndPoint, buffer, offset, length);
  91. }
  92. }
  93. else
  94. {
  95. if (WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || WaitingOptions.AdapterFilter == AdapterFilter.SendAdapter)
  96. {
  97. Client.Send(buffer, offset, length);
  98. }
  99. else
  100. {
  101. Client.DefaultSend(buffer, offset, length);
  102. }
  103. }
  104. m_waitData.SetCancellationToken(token);
  105. switch (m_waitData.Wait(timeout))
  106. {
  107. case WaitDataStatus.SetRunning:
  108. return m_waitData.WaitResult;
  109. case WaitDataStatus.Overtime:
  110. throw new TimeoutException();
  111. case WaitDataStatus.Canceled:
  112. {
  113. if (this.WaitingOptions.ThrowBreakException && this.breaked)
  114. {
  115. throw new Exception("等待已终止。可能是客户端已掉线,或者被注销。");
  116. }
  117. return default;
  118. }
  119. case WaitDataStatus.Default:
  120. case WaitDataStatus.Disposed:
  121. default:
  122. throw new Exception(TouchSocketStatus.UnknownError.GetDescription());
  123. }
  124. }
  125. finally
  126. {
  127. if (this.WaitingOptions.BreakTrigger && this.Client is ITcpClientBase tcpClient)
  128. {
  129. tcpClient.Disconnected -= this.OnDisconnected;
  130. }
  131. if (WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter)
  132. {
  133. Client.OnHandleReceivedData -= OnHandleReceivedData;
  134. }
  135. else
  136. {
  137. Client.OnHandleRawBuffer -= OnHandleRawBuffer;
  138. }
  139. }
  140. }
  141. }
  142. /// <summary>
  143. /// 发送字节流
  144. /// </summary>
  145. /// <param name="buffer">数据缓存区</param>
  146. /// <param name="timeout">超时时间</param>
  147. /// <param name="token">取消令箭</param>
  148. /// <exception cref="NotConnectedException">客户端没有连接</exception>
  149. /// <exception cref="OverlengthException">发送数据超长</exception>
  150. /// <exception cref="Exception">其他异常</exception>
  151. /// <returns>返回的数据</returns>
  152. public ResponsedData SendThenResponse(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default)
  153. {
  154. return SendThenResponse(buffer, 0, buffer.Length, timeout, token);
  155. }
  156. /// <summary>
  157. /// 发送流中的有效数据
  158. /// </summary>
  159. /// <param name="byteBlock">数据块载体</param>
  160. /// <param name="timeout">超时时间</param>
  161. /// <param name="token">取消令箭</param>
  162. /// <exception cref="NotConnectedException">客户端没有连接</exception>
  163. /// <exception cref="OverlengthException">发送数据超长</exception>
  164. /// <exception cref="Exception">其他异常</exception>
  165. /// <returns>返回的数据</returns>
  166. public ResponsedData SendThenResponse(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken token = default)
  167. {
  168. return SendThenResponse(byteBlock.Buffer, 0, byteBlock.Len, timeout, token);
  169. }
  170. /// <summary>
  171. /// 异步发送
  172. /// </summary>
  173. /// <param name="buffer">数据缓存区</param>
  174. /// <param name="offset">偏移</param>
  175. /// <param name="length">长度</param>
  176. /// <param name="timeout">超时时间</param>
  177. /// <param name="token">取消令箭</param>
  178. /// <exception cref="NotConnectedException">客户端没有连接</exception>
  179. /// <exception cref="OverlengthException">发送数据超长</exception>
  180. /// <exception cref="Exception">其他异常</exception>
  181. /// <returns>返回的数据</returns>
  182. public Task<ResponsedData> SendThenResponseAsync(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken token = default)
  183. {
  184. return EasyTask.Run(() =>
  185. {
  186. return SendThenResponse(buffer, offset, length, timeout, token);
  187. });
  188. }
  189. /// <summary>
  190. /// 异步发送
  191. /// </summary>
  192. /// <param name="buffer">数据缓存区</param>
  193. /// <param name="timeout">超时时间</param>
  194. /// <param name="token">取消令箭</param>
  195. /// <exception cref="NotConnectedException">客户端没有连接</exception>
  196. /// <exception cref="OverlengthException">发送数据超长</exception>
  197. /// <exception cref="Exception">其他异常</exception>
  198. /// <returns>返回的数据</returns>
  199. public Task<ResponsedData> SendThenResponseAsync(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default)
  200. {
  201. return EasyTask.Run(() =>
  202. {
  203. return SendThenResponse(buffer, timeout, token);
  204. });
  205. }
  206. /// <summary>
  207. /// 异步发送
  208. /// </summary>
  209. /// <param name="byteBlock">数据块载体</param>
  210. /// <param name="timeout">超时时间</param>
  211. /// <param name="token">取消令箭</param>
  212. /// <exception cref="NotConnectedException">客户端没有连接</exception>
  213. /// <exception cref="OverlengthException">发送数据超长</exception>
  214. /// <exception cref="Exception">其他异常</exception>
  215. /// <returns>返回的数据</returns>
  216. public Task<ResponsedData> SendThenResponseAsync(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken token = default)
  217. {
  218. return EasyTask.Run(() =>
  219. {
  220. return SendThenResponse(byteBlock, timeout, token);
  221. });
  222. }
  223. /// <summary>
  224. /// 发送字节流
  225. /// </summary>
  226. /// <param name="buffer">数据缓存区</param>
  227. /// <param name="offset">偏移</param>
  228. /// <param name="length">长度</param>
  229. /// <param name="timeout">超时时间</param>
  230. /// <param name="token">取消令箭</param>
  231. /// <exception cref="NotConnectedException">客户端没有连接</exception>
  232. /// <exception cref="OverlengthException">发送数据超长</exception>
  233. /// <exception cref="Exception">其他异常</exception>
  234. /// <returns>返回的数据</returns>
  235. public byte[] SendThenReturn(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken token = default)
  236. {
  237. return SendThenResponse(buffer, offset, length, timeout, token).Data;
  238. }
  239. /// <summary>
  240. /// 发送字节流
  241. /// </summary>
  242. /// <param name="buffer">数据缓存区</param>
  243. /// <param name="timeout">超时时间</param>
  244. /// <param name="token">取消令箭</param>
  245. /// <exception cref="NotConnectedException">客户端没有连接</exception>
  246. /// <exception cref="OverlengthException">发送数据超长</exception>
  247. /// <exception cref="Exception">其他异常</exception>
  248. /// <returns>返回的数据</returns>
  249. public byte[] SendThenReturn(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default)
  250. {
  251. return SendThenReturn(buffer, 0, buffer.Length, timeout, token);
  252. }
  253. /// <summary>
  254. /// 发送流中的有效数据
  255. /// </summary>
  256. /// <param name="byteBlock">数据块载体</param>
  257. /// <param name="timeout">超时时间</param>
  258. /// <param name="token">取消令箭</param>
  259. /// <exception cref="NotConnectedException">客户端没有连接</exception>
  260. /// <exception cref="OverlengthException">发送数据超长</exception>
  261. /// <exception cref="Exception">其他异常</exception>
  262. /// <returns>返回的数据</returns>
  263. public byte[] SendThenReturn(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken token = default)
  264. {
  265. return SendThenReturn(byteBlock.Buffer, 0, byteBlock.Len, timeout, token);
  266. }
  267. /// <summary>
  268. /// 异步发送
  269. /// </summary>
  270. /// <param name="buffer">数据缓存区</param>
  271. /// <param name="offset">偏移</param>
  272. /// <param name="length">长度</param>
  273. /// <param name="timeout">超时时间</param>
  274. /// <param name="token">取消令箭</param>
  275. /// <exception cref="NotConnectedException">客户端没有连接</exception>
  276. /// <exception cref="OverlengthException">发送数据超长</exception>
  277. /// <exception cref="Exception">其他异常</exception>
  278. /// <returns>返回的数据</returns>
  279. public Task<byte[]> SendThenReturnAsync(byte[] buffer, int offset, int length, int timeout = 1000 * 5, CancellationToken token = default)
  280. {
  281. return EasyTask.Run(() =>
  282. {
  283. return SendThenReturn(buffer, offset, length, timeout, token);
  284. });
  285. }
  286. /// <summary>
  287. /// 异步发送
  288. /// </summary>
  289. /// <param name="buffer">数据缓存区</param>
  290. /// <param name="timeout">超时时间</param>
  291. /// <param name="token">取消令箭</param>
  292. /// <exception cref="NotConnectedException">客户端没有连接</exception>
  293. /// <exception cref="OverlengthException">发送数据超长</exception>
  294. /// <exception cref="Exception">其他异常</exception>
  295. /// <returns>返回的数据</returns>
  296. public Task<byte[]> SendThenReturnAsync(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default)
  297. {
  298. return EasyTask.Run(() =>
  299. {
  300. return SendThenReturn(buffer, timeout, token);
  301. });
  302. }
  303. /// <summary>
  304. /// 异步发送
  305. /// </summary>
  306. /// <param name="byteBlock">数据块载体</param>
  307. /// <param name="timeout">超时时间</param>
  308. /// <param name="token">取消令箭</param>
  309. /// <exception cref="NotConnectedException">客户端没有连接</exception>
  310. /// <exception cref="OverlengthException">发送数据超长</exception>
  311. /// <exception cref="Exception">其他异常</exception>
  312. /// <returns>返回的数据</returns>
  313. public Task<byte[]> SendThenReturnAsync(ByteBlock byteBlock, int timeout = 1000 * 5, CancellationToken token = default)
  314. {
  315. return EasyTask.Run(() =>
  316. {
  317. return SendThenReturn(byteBlock, timeout, token);
  318. });
  319. }
  320. protected override void Dispose(bool disposing)
  321. {
  322. this.Client = default;
  323. this.m_waitData.SafeDispose();
  324. base.Dispose(disposing);
  325. }
  326. private void OnDisconnected(ITcpClientBase client, DisconnectEventArgs e)
  327. {
  328. breaked = true;
  329. this.m_waitData.Cancel();
  330. }
  331. private bool OnHandleRawBuffer(ByteBlock byteBlock)
  332. {
  333. ResponsedData responsedData = new ResponsedData(byteBlock.ToArray(), null);
  334. return !m_waitData.Set(responsedData);
  335. }
  336. /// <summary>
  337. /// <inheritdoc/>
  338. /// </summary>
  339. /// <param name="byteBlock"></param>
  340. /// <param name="requestInfo"></param>
  341. private bool OnHandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)
  342. {
  343. ResponsedData responsedData;
  344. if (byteBlock != null)
  345. {
  346. responsedData = new ResponsedData(byteBlock.ToArray(), requestInfo);
  347. }
  348. else
  349. {
  350. responsedData = new ResponsedData(null, requestInfo);
  351. }
  352. return !m_waitData.Set(responsedData);
  353. }
  354. }
  355. }