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.
|
|
using Apewer; using Apewer.Internals; using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading;
namespace Apewer.Network {
/// <summary>TCP 客户端。</summary>
public class TcpClient {
#region event
/// <summary>Exception。</summary>
public Event<Exception> Excepted { get; set; }
/// <summary>已发送数据。</summary>
public Event<byte[]> Sent { get; set; }
/// <summary>已接收数据。</summary>
public Event<byte[]> Received { get; set; }
/// <summary>已连接。</summary>
public Event Connected { get; set; }
/// <summary>已断开。</summary>
public Event Closed { get; set; }
#endregion
#region definition
private Thread _listener = null; private Thread _provider = null; private Socket _socket = null; private Queue<byte[]> _queue = null;
// private AutoResetEvent _are = null;
private bool _break = false; private int _timeout = 0;
private string _localip, _remoteip; private int _localport = 0, _remoteport = 0;
private bool _background = true;
/// <summary></summary>
internal object Tag { get; set; }
/// <summary>构造函数。</summary>
public TcpClient() { RemoteIP = "127.0.0.1"; RemotePort = 0; }
/// <summary>构造函数。</summary>
public TcpClient(string ip, int port, int timeout = 0) { RemoteIP = ip; RemotePort = port; Timeout = timeout; }
#endregion
#region accessor
/// <summary>获取或设置监听线程是否为后台线程,默认为“是”。</summary>
public bool Background { get { return _background; } set { _background = value; try { if (_listener != null) _listener.IsBackground = value; } catch (Exception ex) { Excepted?.Invoke(this, ex); } } }
/// <summary>获取或设置远程计算机的 IP 地址。</summary>
public string RemoteIP { get { return _remoteip; } set { string ip = value; if (!NetworkUtility.IsIP(ip)) ip = NetworkUtility.Resolve(ip); if (!NetworkUtility.IsIP(ip)) ip = "127.0.0.1"; _remoteip = ip; } }
/// <summary>获取或设置远程计算机的 TCP 端口号。</summary>
public int RemotePort { get { return _remoteport; } set { int port = value; if (port < 0) port = 0; if (port > 65535) port = 65535; _remoteport = port; } }
/// <summary>获取或设置本地计算机的 IP 地址。</summary>
public string LocalIP { get { return _localip; } private set { _localip = string.IsNullOrEmpty(value) ? "" : value; } }
/// <summary>获取或设置本地计算机的 TCP 端口号。</summary>
public int LocalPort { get { return _localport; } private set { int port = value; if (port < 0) port = 0; if (port > 65535) port = 65535; _localport = port; } }
/// <summary>获取或设置超时时间。</summary>
public int Timeout { get { return _timeout; } set { _timeout = (value > 0) ? value : 0; } }
/// <summary>开始连接,并初始化发送队列。</summary>
public void Start(bool inBackground = false) { Close(false); _queue = new Queue<byte[]>();
if (!inBackground) { _provider = new Thread(Provider); _provider.IsBackground = true; _provider.Start(); return; }
Provider(); // _are.WaitOne(1000);
}
/// <summary>断开连接。</summary>
/// <param name="event">是否引导 Closed 事件。</param>
public void Close(bool @event = true) { CloseThread(ref _provider); CloseThread(ref _listener); CloseSocket(); CloseQueue(); _queue = null; // _are = null;
if (@event) Closed?.Invoke(this); }
/// <summary>向服务端发送数据。</summary>
/// <param name="bytes">字节数组。</param>
public bool Send(byte[] bytes) { if (_socket != null) { _queue.Enqueue(bytes); return true; } else { var ex = new SocketException(10057); Excepted?.Invoke(this, ex); return false; } }
/// <summary>是否已连接。</summary>
public bool Online { get { try { if (_socket != null) return _socket.Connected; } catch (Exception ex) { Excepted?.Invoke(this, ex); } return false; } }
#endregion
#region logic
private void Listener() { var buffer = new byte[TcpBuffer.Size]; var length = 0; while (true) { try { if (_socket.Poll(50, SelectMode.SelectWrite)) { _socket.Blocking = true; length = _socket.Receive(buffer); if (length > 0) { var bytes = new byte[length]; Array.Copy(buffer, bytes, length); Received?.Invoke(this, bytes); } else { if (_socket != null) break; } } } catch (SocketException ex) { if (ex.ErrorCode != 10060) Excepted?.Invoke(this, ex); if (ex.ErrorCode == 10054) break; } catch (Exception ex) { Excepted?.Invoke(this, ex); // break;
} } if (_provider != null) { if (_provider.IsAlive) _provider.Abort(); _provider = null; } if (_socket != null) { _socket.Disconnect(true); _socket.Close(); _socket = null; } CloseThread(ref _provider); CloseSocket(); CloseQueue(); Closed?.Invoke(this); }
private void Provider() { _break = false; _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); if (_timeout > 0) _socket.SendTimeout = _timeout; if (_timeout > 0) _socket.ReceiveTimeout = _timeout; //_are = new AutoResetEvent(false);
try { _socket.Blocking = true; _socket.Connect(_remoteip, _remoteport); if (_socket.Connected) { _socket.SendBufferSize = TcpBuffer.Size; _socket.ReceiveBufferSize = TcpBuffer.Size; var rep = (IPEndPoint)_socket.RemoteEndPoint; var lep = (IPEndPoint)_socket.LocalEndPoint; _remoteip = rep.Address.ToString(); _localip = lep.Address.ToString(); _localport = lep.Port;
Connected?.Invoke(this); _listener = new Thread(Listener); _listener.Start(); // _are.Set();
} else { Close(); return; } } catch (Exception ex) { Excepted?.Invoke(this, ex); }
while ((!_break) && (_socket != null)) {
if (_queue.Count > 0) { var bytes = _queue.Dequeue(); if (bytes.Length > 0) { try { _socket.Send(bytes); Sent?.Invoke(this, bytes); } catch (Exception ex) { Excepted?.Invoke(this, ex); } } else { Thread.Sleep(1); } } } }
private void CloseSocket() { if (_socket != null) { try { _socket.Disconnect(false); _socket.Close(); } catch (SocketException ex) { Excepted?.Invoke(this, ex); } catch (Exception ex) { Excepted?.Invoke(this, ex); } _socket = null; } }
private void CloseThread(ref Thread thread) { if (thread != null) { if (thread.IsAlive) thread.Abort(); thread = null; } }
private void CloseQueue() { if (_queue != null) _queue.Clear(); }
#endregion
} }
|