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.

360 lines
10 KiB

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