You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

353 lines
9.9 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. using Apewer;
  2. using Apewer.Internals;
  3. using System;
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using System.IO;
  7. using System.Net;
  8. using System.Net.Sockets;
  9. using System.Text;
  10. using System.Threading;
  11. namespace Apewer.Network
  12. {
  13. /// <summary>TCP 客户端。</summary>
  14. public class TcpClient
  15. {
  16. #region event
  17. /// <summary>Exception。</summary>
  18. public Event<Exception> Excepted { get; set; }
  19. /// <summary>已发送数据。</summary>
  20. public Event<byte[]> Sent { get; set; }
  21. /// <summary>已接收数据。</summary>
  22. public Event<byte[]> Received { get; set; }
  23. /// <summary>已连接。</summary>
  24. public Event Connected { get; set; }
  25. /// <summary>已断开。</summary>
  26. public Event Closed { get; set; }
  27. #endregion
  28. #region definition
  29. private Thread _listener = null;
  30. private Thread _provider = null;
  31. private Socket _socket = null;
  32. private Queue<byte[]> _queue = null;
  33. // private AutoResetEvent _are = null;
  34. private bool _break = false;
  35. private int _timeout = 0;
  36. private string _localip, _remoteip;
  37. private int _localport = 0, _remoteport = 0;
  38. private bool _background = true;
  39. /// <summary></summary>
  40. internal object Tag { get; set; }
  41. /// <summary>构造函数。</summary>
  42. public TcpClient()
  43. {
  44. RemoteIP = "127.0.0.1";
  45. RemotePort = 0;
  46. }
  47. /// <summary>构造函数。</summary>
  48. public TcpClient(string ip, int port, int timeout = 0)
  49. {
  50. RemoteIP = ip;
  51. RemotePort = port;
  52. Timeout = timeout;
  53. }
  54. #endregion
  55. #region accessor
  56. /// <summary>获取或设置监听线程是否为后台线程,默认为“是”。</summary>
  57. public bool Background
  58. {
  59. get { return _background; }
  60. set
  61. {
  62. _background = value;
  63. try { if (_listener != null) _listener.IsBackground = value; }
  64. catch (Exception ex) { Excepted?.Invoke(this, ex); }
  65. }
  66. }
  67. /// <summary>获取或设置远程计算机的 IP 地址。</summary>
  68. public string RemoteIP
  69. {
  70. get { return _remoteip; }
  71. set
  72. {
  73. string ip = value;
  74. if (!NetworkUtility.IsIP(ip)) ip = NetworkUtility.Resolve(ip);
  75. if (!NetworkUtility.IsIP(ip)) ip = "127.0.0.1";
  76. _remoteip = ip;
  77. }
  78. }
  79. /// <summary>获取或设置远程计算机的 TCP 端口号。</summary>
  80. public int RemotePort
  81. {
  82. get { return _remoteport; }
  83. set
  84. {
  85. int port = value;
  86. if (port < 0) port = 0;
  87. if (port > 65535) port = 65535;
  88. _remoteport = port;
  89. }
  90. }
  91. /// <summary>获取或设置本地计算机的 IP 地址。</summary>
  92. public string LocalIP
  93. {
  94. get { return _localip; }
  95. private set { _localip = string.IsNullOrEmpty(value) ? "" : value; }
  96. }
  97. /// <summary>获取或设置本地计算机的 TCP 端口号。</summary>
  98. public int LocalPort
  99. {
  100. get { return _localport; }
  101. private set
  102. {
  103. int port = value;
  104. if (port < 0) port = 0;
  105. if (port > 65535) port = 65535;
  106. _localport = port;
  107. }
  108. }
  109. /// <summary>获取或设置超时时间。</summary>
  110. public int Timeout
  111. {
  112. get { return _timeout; }
  113. set { _timeout = (value > 0) ? value : 0; }
  114. }
  115. /// <summary>开始连接,并初始化发送队列。</summary>
  116. public void Start(bool inBackground = false)
  117. {
  118. Close(false);
  119. _queue = new Queue<byte[]>();
  120. if (!inBackground)
  121. {
  122. _provider = new Thread(Provider);
  123. _provider.IsBackground = true;
  124. _provider.Start();
  125. return;
  126. }
  127. Provider();
  128. // _are.WaitOne(1000);
  129. }
  130. /// <summary>断开连接。</summary>
  131. /// <param name="event">是否引导 Closed 事件。</param>
  132. public void Close(bool @event = true)
  133. {
  134. CloseThread(ref _provider);
  135. CloseThread(ref _listener);
  136. CloseSocket();
  137. CloseQueue();
  138. _queue = null;
  139. // _are = null;
  140. if (@event) Closed?.Invoke(this);
  141. }
  142. /// <summary>向服务端发送数据。</summary>
  143. /// <param name="bytes">字节数组。</param>
  144. public bool Send(byte[] bytes)
  145. {
  146. if (_socket != null)
  147. {
  148. _queue.Enqueue(bytes);
  149. return true;
  150. }
  151. else
  152. {
  153. var ex = new SocketException(10057);
  154. Excepted?.Invoke(this, ex);
  155. return false;
  156. }
  157. }
  158. /// <summary>是否已连接。</summary>
  159. public bool Online
  160. {
  161. get
  162. {
  163. try { if (_socket != null) return _socket.Connected; }
  164. catch (Exception ex) { Excepted?.Invoke(this, ex); }
  165. return false;
  166. }
  167. }
  168. #endregion
  169. #region logic
  170. private void Listener()
  171. {
  172. var buffer = new byte[TcpBuffer.Size];
  173. var length = 0;
  174. while (true)
  175. {
  176. try
  177. {
  178. if (_socket.Poll(50, SelectMode.SelectWrite))
  179. {
  180. _socket.Blocking = true;
  181. length = _socket.Receive(buffer);
  182. if (length > 0)
  183. {
  184. var bytes = new byte[length];
  185. Array.Copy(buffer, bytes, length);
  186. Received?.Invoke(this, bytes);
  187. }
  188. else
  189. {
  190. if (_socket != null) break;
  191. }
  192. }
  193. }
  194. catch (SocketException ex)
  195. {
  196. if (ex.ErrorCode != 10060) Excepted?.Invoke(this, ex);
  197. if (ex.ErrorCode == 10054) break;
  198. }
  199. catch (Exception ex)
  200. {
  201. Excepted?.Invoke(this, ex);
  202. // break;
  203. }
  204. }
  205. if (_provider != null)
  206. {
  207. if (_provider.IsAlive) _provider.Abort();
  208. _provider = null;
  209. }
  210. if (_socket != null)
  211. {
  212. _socket.Disconnect(true);
  213. _socket.Close();
  214. _socket = null;
  215. }
  216. CloseThread(ref _provider);
  217. CloseSocket();
  218. CloseQueue();
  219. Closed?.Invoke(this);
  220. }
  221. private void Provider()
  222. {
  223. _break = false;
  224. _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  225. if (_timeout > 0) _socket.SendTimeout = _timeout;
  226. if (_timeout > 0) _socket.ReceiveTimeout = _timeout;
  227. //_are = new AutoResetEvent(false);
  228. try
  229. {
  230. _socket.Blocking = true;
  231. _socket.Connect(_remoteip, _remoteport);
  232. if (_socket.Connected)
  233. {
  234. _socket.SendBufferSize = TcpBuffer.Size;
  235. _socket.ReceiveBufferSize = TcpBuffer.Size;
  236. var rep = (IPEndPoint)_socket.RemoteEndPoint;
  237. var lep = (IPEndPoint)_socket.LocalEndPoint;
  238. _remoteip = rep.Address.ToString();
  239. _localip = lep.Address.ToString();
  240. _localport = lep.Port;
  241. Connected?.Invoke(this);
  242. _listener = new Thread(Listener);
  243. _listener.Start();
  244. // _are.Set();
  245. }
  246. else
  247. {
  248. Close();
  249. return;
  250. }
  251. }
  252. catch (Exception ex)
  253. {
  254. Excepted?.Invoke(this, ex);
  255. }
  256. while ((!_break) && (_socket != null))
  257. {
  258. if (_queue.Count > 0)
  259. {
  260. var bytes = _queue.Dequeue();
  261. if (bytes.Length > 0)
  262. {
  263. try
  264. {
  265. _socket.Send(bytes);
  266. Sent?.Invoke(this, bytes);
  267. }
  268. catch (Exception ex)
  269. {
  270. Excepted?.Invoke(this, ex);
  271. }
  272. }
  273. else
  274. {
  275. Thread.Sleep(1);
  276. }
  277. }
  278. }
  279. }
  280. private void CloseSocket()
  281. {
  282. if (_socket != null)
  283. {
  284. try
  285. {
  286. _socket.Disconnect(false);
  287. _socket.Close();
  288. }
  289. catch (SocketException ex) { Excepted?.Invoke(this, ex); }
  290. catch (Exception ex) { Excepted?.Invoke(this, ex); }
  291. _socket = null;
  292. }
  293. }
  294. private void CloseThread(ref Thread thread)
  295. {
  296. if (thread != null)
  297. {
  298. if (thread.IsAlive) thread.Abort();
  299. thread = null;
  300. }
  301. }
  302. private void CloseQueue()
  303. {
  304. if (_queue != null) _queue.Clear();
  305. }
  306. #endregion
  307. }
  308. }