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
360 lines
10 KiB
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 Event<Exception> Excepted;
|
|
|
|
/// <summary>已发送数据。</summary>
|
|
public event Event<byte[]> Sent;
|
|
|
|
/// <summary>已接收数据。</summary>
|
|
public event Event<byte[]> Received;
|
|
|
|
/// <summary>已连接。</summary>
|
|
public event Event Connected;
|
|
|
|
/// <summary>已断开。</summary>
|
|
public event Event Closed;
|
|
|
|
#region raise
|
|
|
|
private void RaiseConnected() { if (Connected != null) Connected(this, new EventArgs()); }
|
|
|
|
private void RaiseClosed() { if (Closed != null) Closed(this, new EventArgs()); }
|
|
|
|
private void RaiseSent(byte[] value) { if (Sent != null) Sent(this, value); }
|
|
|
|
private void RaiseReceived(byte[] value) { if (Received != null) Received(this, value); }
|
|
|
|
private void RaiseExcepted(Exception value) { if (Excepted != null) Excepted(this, value); }
|
|
|
|
#endregion
|
|
|
|
#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 = 1000;
|
|
|
|
private string _localip, _remoteip;
|
|
private int _localport = 0, _remoteport = 0;
|
|
|
|
private bool _background = true;
|
|
|
|
/// <summary>构造函数。</summary>
|
|
public TcpClient()
|
|
{
|
|
RemoteIP = "127.0.0.1";
|
|
RemotePort = 0;
|
|
Timeout = 1000;
|
|
}
|
|
|
|
/// <summary>构造函数。</summary>
|
|
public TcpClient(string ip, int port, int timeout = 1000)
|
|
{
|
|
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 argex) { RaiseExcepted(argex); }
|
|
}
|
|
}
|
|
|
|
/// <summary>获取或设置远程计算机的 IP 地址。</summary>
|
|
public string RemoteIP
|
|
{
|
|
get { return _remoteip; }
|
|
set
|
|
{
|
|
string vip = value;
|
|
if (!NetworkUtility.IsIP(vip)) vip = NetworkUtility.Resolve(vip);
|
|
if (!NetworkUtility.IsIP(vip)) vip = "127.0.0.1";
|
|
_remoteip = vip;
|
|
}
|
|
}
|
|
|
|
/// <summary>获取或设置远程计算机的 TCP 端口号。</summary>
|
|
public int RemotePort
|
|
{
|
|
get { return _remoteport; }
|
|
set
|
|
{
|
|
int vport = value;
|
|
if (vport < 0) vport = 0;
|
|
if (vport > 65535) vport = 65535;
|
|
_remoteport = vport;
|
|
}
|
|
}
|
|
|
|
/// <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 vport = value;
|
|
if (vport < 0) vport = 0;
|
|
if (vport > 65535) vport = 65535;
|
|
_localport = vport;
|
|
}
|
|
}
|
|
|
|
/// <summary>获取或设置超时时间。</summary>
|
|
public int Timeout
|
|
{
|
|
get { return _timeout; }
|
|
set { _timeout = (value > 0) ? value : 1; }
|
|
}
|
|
|
|
/// <summary>开始连接,并初始化发送队列。</summary>
|
|
public void Start()
|
|
{
|
|
Close(false);
|
|
_queue = new Queue<byte[]>();
|
|
|
|
_provider = new Thread(Provider);
|
|
_provider.IsBackground = true;
|
|
_provider.Start();
|
|
// _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) RaiseClosed();
|
|
}
|
|
|
|
/// <summary>向服务端发送数据。</summary>
|
|
/// <param name="bytes">字节数组。</param>
|
|
public bool Send(byte[] bytes)
|
|
{
|
|
if (_socket != null)
|
|
{
|
|
_queue.Enqueue(bytes);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
var vse = new SocketException(10057);
|
|
RaiseExcepted(vse);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// <summary>是否已连接。</summary>
|
|
public bool Online
|
|
{
|
|
get
|
|
{
|
|
try { if (_socket != null) return _socket.Connected; }
|
|
catch (Exception argex) { RaiseExcepted(argex); }
|
|
return false;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region logic
|
|
|
|
private void Listener()
|
|
{
|
|
var vb = new byte[TcpBuffer.Size];
|
|
var vf = 0;
|
|
while (true)
|
|
{
|
|
try
|
|
{
|
|
if (_socket.Poll(50, SelectMode.SelectWrite))
|
|
{
|
|
_socket.Blocking = true;
|
|
vf = _socket.Receive(vb);
|
|
if (vf > 0)
|
|
{
|
|
var vms = new MemoryStream(vb);
|
|
vms.SetLength(vf);
|
|
RaiseReceived(vms.ToArray());
|
|
vms.Dispose();
|
|
}
|
|
else
|
|
{
|
|
if (_socket != null) break;
|
|
}
|
|
}
|
|
}
|
|
catch (SocketException argEx)
|
|
{
|
|
if (argEx.ErrorCode != 10060) RaiseExcepted(argEx);
|
|
if (argEx.ErrorCode == 10054) break;
|
|
}
|
|
catch (Exception argEx)
|
|
{
|
|
RaiseExcepted(argEx);
|
|
// 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();
|
|
RaiseClosed();
|
|
}
|
|
|
|
private void Provider()
|
|
{
|
|
_break = false;
|
|
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
|
_socket.SendTimeout = _timeout;
|
|
_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 vrep = (IPEndPoint)_socket.RemoteEndPoint;
|
|
var vlep = (IPEndPoint)_socket.LocalEndPoint;
|
|
_remoteip = vrep.Address.ToString();
|
|
_localip = vlep.Address.ToString();
|
|
_localport = vlep.Port;
|
|
|
|
RaiseConnected();
|
|
_listener = new Thread(Listener);
|
|
_listener.Start();
|
|
// _are.Set();
|
|
}
|
|
else
|
|
{
|
|
Close();
|
|
return;
|
|
}
|
|
}
|
|
catch (Exception argEx)
|
|
{
|
|
RaiseExcepted(argEx);
|
|
}
|
|
|
|
while ((!_break) && (_socket != null))
|
|
{
|
|
|
|
if (_queue.Count > 0)
|
|
{
|
|
var vb = _queue.Dequeue();
|
|
if (vb.Length > 0)
|
|
{
|
|
try
|
|
{
|
|
_socket.Send(vb);
|
|
RaiseSent(vb);
|
|
}
|
|
catch (Exception argEx)
|
|
{
|
|
RaiseExcepted(argEx);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Thread.Sleep(1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CloseSocket()
|
|
{
|
|
if (_socket != null)
|
|
{
|
|
try
|
|
{
|
|
_socket.Disconnect(false);
|
|
_socket.Close();
|
|
}
|
|
catch (SocketException argEx) { RaiseExcepted(argEx); }
|
|
catch (Exception argEx) { RaiseExcepted(argEx); }
|
|
_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
|
|
|
|
}
|
|
}
|
|
|