TcpService.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723
  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.Collections.Generic;
  15. using System.Linq;
  16. using System.Net.Sockets;
  17. using System.Threading;
  18. using TouchSocket.Core;
  19. using TouchSocket.Resources;
  20. namespace TouchSocket.Sockets
  21. {
  22. /// <summary>
  23. /// TCP泛型服务器,由客户自己指定<see cref="SocketClient"/>类型。
  24. /// </summary>
  25. public class TcpService<TClient> : TcpServiceBase, ITcpService<TClient> where TClient : SocketClient
  26. {
  27. /// <summary>
  28. /// 构造函数
  29. /// </summary>
  30. public TcpService()
  31. {
  32. m_socketClients = new SocketClientCollection();
  33. m_getDefaultNewID = () =>
  34. {
  35. return Interlocked.Increment(ref m_nextId).ToString();
  36. };
  37. }
  38. #region 变量
  39. private readonly SocketClientCollection m_socketClients;
  40. private int m_backlog;
  41. private TouchSocketConfig m_config;
  42. private Func<string> m_getDefaultNewID;
  43. private int m_maxCount;
  44. private NetworkMonitor[] m_monitors;
  45. private long m_nextId;
  46. private ReceiveType m_receiveType;
  47. private ServerState m_serverState;
  48. private bool m_usePlugin;
  49. private bool m_useSsl;
  50. #endregion 变量
  51. #region 属性
  52. /// <summary>
  53. /// 获取服务器配置
  54. /// </summary>
  55. public override TouchSocketConfig Config => m_config;
  56. /// <summary>
  57. /// <inheritdoc/>
  58. /// </summary>
  59. public override IContainer Container => Config?.Container;
  60. /// <summary>
  61. /// <inheritdoc/>
  62. /// </summary>
  63. public override Func<string> GetDefaultNewID => m_getDefaultNewID;
  64. /// <summary>
  65. /// <inheritdoc/>
  66. /// </summary>
  67. public override int MaxCount => m_maxCount;
  68. /// <summary>
  69. /// <inheritdoc/>
  70. /// </summary>
  71. public override NetworkMonitor[] Monitors => m_monitors;
  72. /// <summary>
  73. /// <inheritdoc/>
  74. /// </summary>
  75. public override IPluginsManager PluginsManager => Config?.PluginsManager;
  76. /// <summary>
  77. /// <inheritdoc/>
  78. /// </summary>
  79. public override string ServerName => Config?.GetValue<string>(TouchSocketConfigExtension.ServerNameProperty);
  80. /// <summary>
  81. /// <inheritdoc/>
  82. /// </summary>
  83. public override ServerState ServerState => m_serverState;
  84. /// <summary>
  85. /// <inheritdoc/>
  86. /// </summary>
  87. public override SocketClientCollection SocketClients => m_socketClients;
  88. /// <summary>
  89. /// <inheritdoc/>
  90. /// </summary>
  91. public override bool UsePlugin => m_usePlugin;
  92. /// <summary>
  93. /// <inheritdoc/>
  94. /// </summary>
  95. public override bool UseSsl => m_useSsl;
  96. #endregion 属性
  97. #region 事件
  98. /// <summary>
  99. /// 用户连接完成
  100. /// </summary>
  101. public TouchSocketEventHandler<TClient> Connected { get; set; }
  102. /// <summary>
  103. /// 有用户连接的时候
  104. /// </summary>
  105. public OperationEventHandler<TClient> Connecting { get; set; }
  106. /// <summary>
  107. /// 有用户断开连接
  108. /// </summary>
  109. public DisconnectEventHandler<TClient> Disconnected { get; set; }
  110. /// <summary>
  111. /// 即将断开连接(仅主动断开时有效)。
  112. /// <para>
  113. /// 当主动调用Close断开时,可通过<see cref="TouchSocketEventArgs.IsPermitOperation"/>终止断开行为。
  114. /// </para>
  115. /// </summary>
  116. public DisconnectEventHandler<TClient> Disconnecting { get; set; }
  117. /// <summary>
  118. /// 当客户端ID被修改时触发。
  119. /// </summary>
  120. public IDChangedEventHandler<TClient> IDChanged { get; set; }
  121. /// <summary>
  122. /// <inheritdoc/>
  123. /// </summary>
  124. /// <param name="socketClient"></param>
  125. /// <param name="e"></param>
  126. protected override sealed void OnClientConnected(ISocketClient socketClient, TouchSocketEventArgs e)
  127. {
  128. OnConnected((TClient)socketClient, e);
  129. }
  130. /// <summary>
  131. /// <inheritdoc/>
  132. /// </summary>
  133. /// <param name="socketClient"></param>
  134. /// <param name="e"></param>
  135. protected override sealed void OnClientConnecting(ISocketClient socketClient, OperationEventArgs e)
  136. {
  137. OnConnecting((TClient)socketClient, e);
  138. }
  139. /// <summary>
  140. /// <inheritdoc/>
  141. /// </summary>
  142. /// <param name="socketClient"></param>
  143. /// <param name="e"></param>
  144. protected override sealed void OnClientDisconnected(ISocketClient socketClient, DisconnectEventArgs e)
  145. {
  146. OnDisconnected((TClient)socketClient, e);
  147. }
  148. /// <summary>
  149. /// <inheritdoc/>
  150. /// </summary>
  151. /// <param name="socketClient"></param>
  152. /// <param name="e"></param>
  153. protected override sealed void OnClientDisconnecting(ISocketClient socketClient, DisconnectEventArgs e)
  154. {
  155. OnDisconnecting((TClient)socketClient, e);
  156. }
  157. /// <summary>
  158. /// <inheritdoc/>
  159. /// </summary>
  160. /// <param name="socketClient"></param>
  161. /// <param name="byteBlock"></param>
  162. /// <param name="requestInfo"></param>
  163. protected override sealed void OnClientReceivedData(ISocketClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo)
  164. {
  165. OnReceived((TClient)socketClient, byteBlock, requestInfo);
  166. }
  167. /// <summary>
  168. /// 客户端连接完成,覆盖父类方法将不会触发事件。
  169. /// </summary>
  170. /// <param name="socketClient"></param>
  171. /// <param name="e"></param>
  172. protected virtual void OnConnected(TClient socketClient, TouchSocketEventArgs e)
  173. {
  174. Connected?.Invoke(socketClient, e);
  175. }
  176. /// <summary>
  177. /// 客户端请求连接,覆盖父类方法将不会触发事件。
  178. /// </summary>
  179. /// <param name="socketClient"></param>
  180. /// <param name="e"></param>
  181. protected virtual void OnConnecting(TClient socketClient, OperationEventArgs e)
  182. {
  183. Connecting?.Invoke(socketClient, e);
  184. }
  185. /// <summary>
  186. /// 客户端断开连接,覆盖父类方法将不会触发事件。
  187. /// </summary>
  188. /// <param name="socketClient"></param>
  189. /// <param name="e"></param>
  190. protected virtual void OnDisconnected(TClient socketClient, DisconnectEventArgs e)
  191. {
  192. Disconnected?.Invoke(socketClient, e);
  193. }
  194. /// <summary>
  195. /// 即将断开连接(仅主动断开时有效)。
  196. /// <para>
  197. /// 当主动调用Close断开时,可通过<see cref="TouchSocketEventArgs.IsPermitOperation"/>终止断开行为。
  198. /// </para>
  199. /// </summary>
  200. /// <param name="socketClient"></param>
  201. /// <param name="e"></param>
  202. protected virtual void OnDisconnecting(TClient socketClient, DisconnectEventArgs e)
  203. {
  204. Disconnecting?.Invoke(socketClient, e);
  205. }
  206. /// <summary>
  207. /// 当收到适配器数据。
  208. /// </summary>
  209. /// <param name="socketClient"></param>
  210. /// <param name="byteBlock"></param>
  211. /// <param name="requestInfo"></param>
  212. protected virtual void OnReceived(TClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo)
  213. {
  214. }
  215. #endregion 事件
  216. /// <summary>
  217. /// <inheritdoc/>
  218. /// </summary>
  219. public override void Clear()
  220. {
  221. string[] ids = GetIDs();
  222. foreach (var item in ids)
  223. {
  224. if (TryGetSocketClient(item, out TClient client))
  225. {
  226. client.Dispose();
  227. }
  228. }
  229. }
  230. /// <summary>
  231. /// 获取当前在线的所有客户端
  232. /// </summary>
  233. /// <returns></returns>
  234. public TClient[] GetClients()
  235. {
  236. var clients = m_socketClients.GetClients().ToArray();
  237. TClient[] clients1 = new TClient[clients.Length];
  238. for (int i = 0; i < clients.Length; i++)
  239. {
  240. clients1[i] = (TClient)clients[i];
  241. }
  242. return clients1;
  243. }
  244. /// <summary>
  245. /// <inheritdoc/>
  246. /// </summary>
  247. /// <param name="oldID"></param>
  248. /// <param name="newID"></param>
  249. /// <exception cref="ClientNotFindException"></exception>
  250. /// <exception cref="Exception"></exception>
  251. public override void ResetID(string oldID, string newID)
  252. {
  253. if (string.IsNullOrEmpty(oldID))
  254. {
  255. throw new ArgumentException($"“{nameof(oldID)}”不能为 null 或空。", nameof(oldID));
  256. }
  257. if (string.IsNullOrEmpty(newID))
  258. {
  259. throw new ArgumentException($"“{nameof(newID)}”不能为 null 或空。", nameof(newID));
  260. }
  261. if (oldID == newID)
  262. {
  263. return;
  264. }
  265. if (m_socketClients.TryGetSocketClient(oldID, out TClient socketClient))
  266. {
  267. socketClient.ResetID(newID);
  268. }
  269. else
  270. {
  271. throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(oldID));
  272. }
  273. }
  274. /// <summary>
  275. /// <inheritdoc/>
  276. /// </summary>
  277. /// <param name="config"></param>
  278. public override IService Setup(TouchSocketConfig config)
  279. {
  280. m_config = config;
  281. if (config.IsUsePlugin)
  282. {
  283. PluginsManager.Raise<IConfigPlugin>(nameof(IConfigPlugin.OnLoadingConfig), this, new ConfigEventArgs(config));
  284. }
  285. LoadConfig(m_config);
  286. if (UsePlugin)
  287. {
  288. PluginsManager.Raise<IConfigPlugin>(nameof(IConfigPlugin.OnLoadedConfig), this, new ConfigEventArgs(config));
  289. }
  290. Container.RegisterTransient<TClient>();
  291. return this;
  292. }
  293. /// <summary>
  294. /// <inheritdoc/>
  295. /// </summary>
  296. /// <param name="port"></param>
  297. public override IService Setup(int port)
  298. {
  299. TouchSocketConfig serviceConfig = new TouchSocketConfig();
  300. serviceConfig.SetListenIPHosts(new IPHost[] { new IPHost(port) });
  301. return Setup(serviceConfig);
  302. }
  303. /// <summary>
  304. ///<inheritdoc/>
  305. /// </summary>
  306. /// <param name="id"></param>
  307. /// <returns></returns>
  308. public override bool SocketClientExist(string id)
  309. {
  310. return SocketClients.SocketClientExist(id);
  311. }
  312. /// <summary>
  313. /// <inheritdoc/>
  314. /// </summary>
  315. /// <exception cref="Exception"></exception>
  316. /// <exception cref="ArgumentNullException"></exception>
  317. /// <exception cref="System.Exception"></exception>
  318. public override IService Start()
  319. {
  320. try
  321. {
  322. IPHost[] iPHosts = Config.GetValue(TouchSocketConfigExtension.ListenIPHostsProperty);
  323. if (iPHosts == null || iPHosts.Length == 0)
  324. {
  325. throw new Exception("IPHosts为空,无法绑定");
  326. }
  327. switch (m_serverState)
  328. {
  329. case ServerState.None:
  330. {
  331. BeginListen(iPHosts);
  332. break;
  333. }
  334. case ServerState.Running:
  335. {
  336. return this;
  337. }
  338. case ServerState.Stopped:
  339. {
  340. BeginListen(iPHosts);
  341. break;
  342. }
  343. case ServerState.Disposed:
  344. {
  345. throw new Exception("无法重新利用已释放对象");
  346. }
  347. }
  348. m_serverState = ServerState.Running;
  349. if (UsePlugin)
  350. {
  351. PluginsManager.Raise<IServicePlugin>(nameof(IServicePlugin.OnStarted), this, new ServiceStateEventArgs(this.m_serverState, default));
  352. }
  353. return this;
  354. }
  355. catch (Exception ex)
  356. {
  357. m_serverState = ServerState.Exception;
  358. if (UsePlugin)
  359. {
  360. PluginsManager.Raise<IServicePlugin>(nameof(IServicePlugin.OnStarted), this, new ServiceStateEventArgs(this.m_serverState, ex) { Message=ex.Message });
  361. }
  362. throw;
  363. }
  364. }
  365. /// <summary>
  366. /// <inheritdoc/>
  367. /// </summary>
  368. public override IService Stop()
  369. {
  370. if (m_monitors != null)
  371. {
  372. foreach (var item in m_monitors)
  373. {
  374. item.Socket?.Dispose();
  375. }
  376. }
  377. m_monitors = null;
  378. Clear();
  379. m_serverState = ServerState.Stopped;
  380. if (UsePlugin)
  381. {
  382. PluginsManager.Raise<IServicePlugin>(nameof(IServicePlugin.OnStoped), this, new ServiceStateEventArgs(this.m_serverState, default));
  383. }
  384. return this;
  385. }
  386. /// <summary>
  387. /// 尝试获取TClient
  388. /// </summary>
  389. /// <param name="id">ID</param>
  390. /// <param name="socketClient">TClient</param>
  391. /// <returns></returns>
  392. public bool TryGetSocketClient(string id, out TClient socketClient)
  393. {
  394. return m_socketClients.TryGetSocketClient(id, out socketClient);
  395. }
  396. /// <summary>
  397. /// <inheritdoc/>
  398. /// </summary>
  399. /// <param name="disposing"></param>
  400. protected override void Dispose(bool disposing)
  401. {
  402. if (!DisposedValue)
  403. {
  404. if (disposing)
  405. {
  406. if (m_monitors != null)
  407. {
  408. foreach (var item in m_monitors)
  409. {
  410. item.Socket?.Dispose();
  411. }
  412. m_monitors = null;
  413. }
  414. Clear();
  415. m_serverState = ServerState.Disposed;
  416. if (UsePlugin)
  417. {
  418. PluginsManager.Raise<IServicePlugin>(nameof(IServicePlugin.OnStoped), this, new ServiceStateEventArgs(this.m_serverState, default));
  419. }
  420. PluginsManager.Clear();
  421. }
  422. }
  423. base.Dispose(disposing);
  424. }
  425. /// <summary>
  426. /// 初始化客户端实例,默认实现为<see cref="Container.Resolve(Type, object[], string)"/>
  427. /// </summary>
  428. /// <returns></returns>
  429. protected virtual TClient GetClientInstence()
  430. {
  431. return Container.Resolve<TClient>();
  432. }
  433. /// <summary>
  434. /// 加载配置
  435. /// </summary>
  436. /// <param name="config"></param>
  437. protected virtual void LoadConfig(TouchSocketConfig config)
  438. {
  439. if (config == null)
  440. {
  441. throw new Exception("配置文件为空");
  442. }
  443. if (config.GetValue(TouchSocketConfigExtension.GetDefaultNewIDProperty) is Func<string> fun)
  444. {
  445. m_getDefaultNewID = fun;
  446. }
  447. m_usePlugin = config.IsUsePlugin;
  448. m_maxCount = config.GetValue(TouchSocketConfigExtension.MaxCountProperty);
  449. m_backlog = config.GetValue(TouchSocketConfigExtension.BacklogProperty);
  450. BufferLength = config.GetValue(TouchSocketConfigExtension.BufferLengthProperty);
  451. m_receiveType = config.GetValue(TouchSocketConfigExtension.ReceiveTypeProperty);
  452. Logger ??= Container.Resolve<ILog>();
  453. if (config.GetValue(TouchSocketConfigExtension.SslOptionProperty) != null)
  454. {
  455. m_useSsl = true;
  456. }
  457. }
  458. /// <summary>
  459. /// 在验证Ssl发送错误时。
  460. /// </summary>
  461. /// <param name="ex"></param>
  462. protected virtual void OnAuthenticatingError(System.Exception ex)
  463. {
  464. }
  465. /// <summary>
  466. /// 在Socket初始化对象后,Bind之前调用。
  467. /// 可用于设置Socket参数。
  468. /// 父类方法可覆盖。
  469. /// </summary>
  470. /// <param name="socket"></param>
  471. protected virtual void PreviewBind(Socket socket)
  472. {
  473. }
  474. private void Args_Completed(object sender, SocketAsyncEventArgs e)
  475. {
  476. if (e.LastOperation == SocketAsyncOperation.Accept)
  477. {
  478. OnAccepted(e);
  479. }
  480. }
  481. private void BeginListen(IPHost[] iPHosts)
  482. {
  483. int threadCount = Config.GetValue(TouchSocketConfigExtension.ThreadCountProperty);
  484. if (threadCount > 0)
  485. {
  486. while (!ThreadPool.SetMinThreads(threadCount, threadCount))
  487. {
  488. if (--threadCount <= 10)
  489. {
  490. break;
  491. }
  492. }
  493. }
  494. List<NetworkMonitor> networkMonitors = new List<NetworkMonitor>();
  495. foreach (var iPHost in iPHosts)
  496. {
  497. Socket socket = new Socket(iPHost.AddressFamily, SocketType.Stream, ProtocolType.Tcp)
  498. {
  499. ReceiveBufferSize = BufferLength,
  500. SendBufferSize = BufferLength
  501. };
  502. if (m_config.GetValue(TouchSocketConfigExtension.ReuseAddressProperty))
  503. {
  504. socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
  505. }
  506. PreviewBind(socket);
  507. socket.Bind(iPHost.EndPoint);
  508. socket.Listen(m_backlog);
  509. networkMonitors.Add(new NetworkMonitor(iPHost, socket));
  510. }
  511. m_monitors = networkMonitors.ToArray();
  512. foreach (var networkMonitor in m_monitors)
  513. {
  514. SocketAsyncEventArgs e = new SocketAsyncEventArgs
  515. {
  516. UserToken = networkMonitor.Socket
  517. };
  518. e.Completed += Args_Completed;
  519. if (!networkMonitor.Socket.AcceptAsync(e))
  520. {
  521. OnAccepted(e);
  522. }
  523. }
  524. }
  525. private void OnAccepted(SocketAsyncEventArgs e)
  526. {
  527. if (!DisposedValue)
  528. {
  529. if (e.SocketError == SocketError.Success && e.AcceptSocket != null)
  530. {
  531. Socket socket = e.AcceptSocket;
  532. socket.ReceiveBufferSize = BufferLength;
  533. socket.SendBufferSize = BufferLength;
  534. if (SocketClients.Count < m_maxCount)
  535. {
  536. SocketInit(socket);
  537. }
  538. else
  539. {
  540. socket.SafeDispose();
  541. Logger.Warning(this, "连接客户端数量已达到设定最大值");
  542. }
  543. }
  544. e.AcceptSocket = null;
  545. try
  546. {
  547. if (!((Socket)e.UserToken).AcceptAsync(e))
  548. {
  549. OnAccepted(e);
  550. }
  551. }
  552. catch
  553. {
  554. e.Dispose();
  555. return;
  556. }
  557. }
  558. }
  559. private void SetClientConfiguration(SocketClient client)
  560. {
  561. client.m_usePlugin = m_usePlugin;
  562. client.Config = m_config;
  563. client.m_service = this;
  564. client.Logger = Container.Resolve<ILog>();
  565. client.m_receiveType = m_receiveType;
  566. client.BufferLength = BufferLength;
  567. if (client.CanSetDataHandlingAdapter)
  568. {
  569. client.SetDataHandlingAdapter(Config.GetValue(TouchSocketConfigExtension.DataHandlingAdapterProperty).Invoke());
  570. }
  571. }
  572. private void SocketInit(Socket socket)
  573. {
  574. try
  575. {
  576. if (Config.GetValue(TouchSocketConfigExtension.NoDelayProperty))
  577. {
  578. socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
  579. }
  580. TClient client = GetClientInstence();
  581. SetClientConfiguration(client);
  582. client.SetSocket(socket);
  583. client.InternalInitialized();
  584. OperationEventArgs args = new OperationEventArgs
  585. {
  586. ID = GetDefaultNewID()
  587. };
  588. client.InternalConnecting(args);//Connecting
  589. if (args.IsPermitOperation)
  590. {
  591. client.m_id = args.ID;
  592. if (SocketClients.TryAdd(client))
  593. {
  594. client.InternalConnected(new MsgEventArgs("客户端成功连接"));
  595. if (!client.MainSocket.Connected)
  596. {
  597. return;
  598. }
  599. if (m_useSsl)
  600. {
  601. try
  602. {
  603. client.BeginReceiveSsl(m_receiveType, (ServiceSslOption)m_config.GetValue(TouchSocketConfigExtension.SslOptionProperty));
  604. }
  605. catch (System.Exception ex)
  606. {
  607. OnAuthenticatingError(ex);
  608. return;
  609. }
  610. }
  611. else
  612. {
  613. client.BeginReceive(m_receiveType);
  614. }
  615. }
  616. else
  617. {
  618. throw new Exception($"ID={client.m_id}重复");
  619. }
  620. }
  621. else
  622. {
  623. socket.SafeDispose();
  624. }
  625. }
  626. catch (Exception ex)
  627. {
  628. socket.SafeDispose();
  629. Logger.Log(LogType.Error, this, "接收新连接错误", ex);
  630. }
  631. }
  632. }
  633. /// <summary>
  634. /// TCP服务器
  635. /// </summary>
  636. public class TcpService : TcpService<SocketClient>
  637. {
  638. /// <summary>
  639. /// 处理数据
  640. /// </summary>
  641. public ReceivedEventHandler<SocketClient> Received { get; set; }
  642. /// <summary>
  643. /// <inheritdoc/>
  644. /// </summary>
  645. /// <param name="socketClient"></param>
  646. /// <param name="byteBlock"></param>
  647. /// <param name="requestInfo"></param>
  648. protected override void OnReceived(SocketClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo)
  649. {
  650. Received?.Invoke(socketClient, byteBlock, requestInfo);
  651. base.OnReceived(socketClient, byteBlock, requestInfo);
  652. }
  653. }
  654. }