|
|
|
@ -0,0 +1,243 @@ |
|
|
|
|
using System; |
|
|
|
|
using System.Collections.Generic; |
|
|
|
|
using System.Diagnostics; |
|
|
|
|
using System.Net; |
|
|
|
|
using System.Net.Sockets; |
|
|
|
|
using System.Text; |
|
|
|
|
using System.Threading; |
|
|
|
|
using System.Timers; |
|
|
|
|
|
|
|
|
|
namespace HeadTailSocketFW |
|
|
|
|
{ |
|
|
|
|
public delegate void BufferReceivedHandler(object sender, byte[] buffer); |
|
|
|
|
public delegate void ConnectionStatusHandler(object sender); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public class ClientSocket |
|
|
|
|
{ |
|
|
|
|
protected readonly int MAX_BUFFER_SIZE = 8 * 1024; |
|
|
|
|
|
|
|
|
|
protected readonly int SOCKET_BUFFER_SIZE = 2 * 1024; // 2KB |
|
|
|
|
protected readonly int SEND_SOCKET_BUFFER_SIZE = 8 * 1024; // 8KB |
|
|
|
|
|
|
|
|
|
protected Socket _socket; |
|
|
|
|
protected byte[] _receiveSocketBuffer; |
|
|
|
|
protected byte[] _sendSocketBuffer; |
|
|
|
|
protected ByteQueue _buffer; |
|
|
|
|
|
|
|
|
|
private ManualResetEvent _sendEvent = new ManualResetEvent(true); |
|
|
|
|
private IPEndPoint _endPoint; |
|
|
|
|
private bool _disposed; |
|
|
|
|
|
|
|
|
|
public bool IsConnected => _socket != null && _socket.Connected; |
|
|
|
|
|
|
|
|
|
public event BufferReceivedHandler OnReceived; |
|
|
|
|
public event ConnectionStatusHandler OnConnected; |
|
|
|
|
public event ConnectionStatusHandler OnDisconnected; |
|
|
|
|
|
|
|
|
|
public bool EnableDebug { get; set; } = false; |
|
|
|
|
|
|
|
|
|
public ClientSocket(int bufferSize = 2, int sendBufferSize = 8) |
|
|
|
|
{ |
|
|
|
|
SOCKET_BUFFER_SIZE = bufferSize * 1024 > MAX_BUFFER_SIZE ? MAX_BUFFER_SIZE : bufferSize * 1024; |
|
|
|
|
SEND_SOCKET_BUFFER_SIZE = sendBufferSize * 1024 > MAX_BUFFER_SIZE ? MAX_BUFFER_SIZE : sendBufferSize * 1024; |
|
|
|
|
|
|
|
|
|
_receiveSocketBuffer = new byte[SOCKET_BUFFER_SIZE]; |
|
|
|
|
_sendSocketBuffer = new byte[SEND_SOCKET_BUFFER_SIZE]; |
|
|
|
|
_buffer = new ByteQueue(MAX_BUFFER_SIZE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public bool Connect(string address, int port) |
|
|
|
|
{ |
|
|
|
|
Disconnect(); |
|
|
|
|
try |
|
|
|
|
{ |
|
|
|
|
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); |
|
|
|
|
IPAddress endPointAddress = IPAddress.Parse(address.Trim()); |
|
|
|
|
_endPoint = new IPEndPoint(endPointAddress, port); |
|
|
|
|
} |
|
|
|
|
catch (Exception ex) |
|
|
|
|
{ |
|
|
|
|
Debug.WriteLine($"[ClientSocket.Connect] {ex.Message}"); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return Reconnect(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public bool Connect(string address, int port, int timeout) |
|
|
|
|
{ |
|
|
|
|
Disconnect(); |
|
|
|
|
try |
|
|
|
|
{ |
|
|
|
|
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); |
|
|
|
|
IPAddress endPointAddress = IPAddress.Parse(address.Trim()); |
|
|
|
|
_endPoint = new IPEndPoint(endPointAddress, port); |
|
|
|
|
_socket.Connect(_endPoint); |
|
|
|
|
_socket.Blocking = true; |
|
|
|
|
} |
|
|
|
|
catch (SocketException sockEx) |
|
|
|
|
{ |
|
|
|
|
Debug.WriteLine($"[ClientSocket.Connect.Socket] {sockEx.Message}"); |
|
|
|
|
if (sockEx.SocketErrorCode != SocketError.WouldBlock) |
|
|
|
|
{ |
|
|
|
|
_socket.Close(); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!_socket.Poll(timeout * 1000, SelectMode.SelectWrite)) |
|
|
|
|
{ |
|
|
|
|
_socket.Close(); |
|
|
|
|
Debug.WriteLine($"[ClientSocket.Connect.Socket] Failed to connect."); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
catch (Exception ex) |
|
|
|
|
{ |
|
|
|
|
Debug.WriteLine($"[ClientSocket.Connect] {ex.Message}"); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public bool Reconnect() |
|
|
|
|
{ |
|
|
|
|
if (_endPoint == null) |
|
|
|
|
throw new Exception("EndPoint is not initialized."); |
|
|
|
|
|
|
|
|
|
if (_socket.Connected) |
|
|
|
|
_socket.Disconnect(true); |
|
|
|
|
|
|
|
|
|
bool isSuccess = false; |
|
|
|
|
try |
|
|
|
|
{ |
|
|
|
|
_socket.Connect(_endPoint); |
|
|
|
|
_socket.BeginReceive(_receiveSocketBuffer, 0, SOCKET_BUFFER_SIZE, SocketFlags.None, ReceiveCallback, this); |
|
|
|
|
isSuccess = true; |
|
|
|
|
} |
|
|
|
|
catch (SocketException sockEx) |
|
|
|
|
{ |
|
|
|
|
Debug.WriteLine($"[ClientSocket.Reconnect.Socket] {sockEx.ToString()}"); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
catch (Exception ex) |
|
|
|
|
{ |
|
|
|
|
Debug.WriteLine($"[ClientSocket.Reconnect] {ex.ToString()}"); |
|
|
|
|
|
|
|
|
|
throw; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (isSuccess && OnConnected != null) |
|
|
|
|
OnConnected(this); |
|
|
|
|
|
|
|
|
|
return isSuccess; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void Disconnect() |
|
|
|
|
{ |
|
|
|
|
if (_socket == null) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
try |
|
|
|
|
{ |
|
|
|
|
_socket.Close(); |
|
|
|
|
_socket = null; |
|
|
|
|
if (OnDisconnected != null) |
|
|
|
|
OnDisconnected(this); |
|
|
|
|
} |
|
|
|
|
catch (Exception) |
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
throw; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protected void ReceiveCallback(IAsyncResult ar) |
|
|
|
|
{ |
|
|
|
|
if (_socket == null) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
try |
|
|
|
|
{ |
|
|
|
|
int receiveCount = _socket.EndReceive(ar); |
|
|
|
|
if (receiveCount == 0) |
|
|
|
|
{ |
|
|
|
|
Disconnect(); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
try |
|
|
|
|
{ |
|
|
|
|
_buffer.Enqueue(_receiveSocketBuffer); |
|
|
|
|
if (EnableDebug) |
|
|
|
|
{ |
|
|
|
|
if (EnableDebug) |
|
|
|
|
Debug.WriteLine($"SocketDebug[{_endPoint.ToString()}] {Encoding.ASCII.GetString(_receiveSocketBuffer)}"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Interpret(); |
|
|
|
|
} |
|
|
|
|
catch (Exception ex) |
|
|
|
|
{ |
|
|
|
|
Debug.WriteLine($"[ClientSocket.ReceiveCallback.Interpret] {ex.Message}"); |
|
|
|
|
_buffer.Clear(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (_socket != null) |
|
|
|
|
_socket.BeginReceive(_receiveSocketBuffer, 0, SOCKET_BUFFER_SIZE, SocketFlags.None, ReceiveCallback, this); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
catch (SocketException sockEx) |
|
|
|
|
{ |
|
|
|
|
Debug.WriteLine($"[ClientSocket.ReceiveCallback.Socket] {sockEx.Message}"); |
|
|
|
|
} |
|
|
|
|
catch (Exception ex) |
|
|
|
|
{ |
|
|
|
|
Debug.WriteLine($"[ClientSocket.ReceiveCallback] {ex.Message}"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protected virtual void Interpret() |
|
|
|
|
{ |
|
|
|
|
RaiseReceivedEvent(this, _buffer.Dequeue(_buffer.Count)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protected void RaiseReceivedEvent(object sender, byte[] buffer) |
|
|
|
|
{ |
|
|
|
|
if (OnReceived != null) |
|
|
|
|
OnReceived(sender, buffer); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public virtual void Send(byte[] data) |
|
|
|
|
{ |
|
|
|
|
byte[] array = new byte[data.Length]; |
|
|
|
|
Array.Copy(data, array, data.Length); |
|
|
|
|
try |
|
|
|
|
{ |
|
|
|
|
_sendEvent.WaitOne(); |
|
|
|
|
_sendEvent.Reset(); |
|
|
|
|
_socket.BeginSend(array, 0, array.Length, SocketFlags.None, SendCallback, this); |
|
|
|
|
} |
|
|
|
|
catch (Exception ex) |
|
|
|
|
{ |
|
|
|
|
Debug.WriteLine($"[ClientSocket.Send] -Message: {Encoding.ASCII.GetString(array)} -Exception: {ex.Message}"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protected void SendCallback(IAsyncResult ar) |
|
|
|
|
{ |
|
|
|
|
_sendEvent.Set(); |
|
|
|
|
try |
|
|
|
|
{ |
|
|
|
|
int sendCount = _socket.EndSend(ar); |
|
|
|
|
} |
|
|
|
|
catch (Exception ex) |
|
|
|
|
{ |
|
|
|
|
Debug.WriteLine($"[ClientSocket.SendCallback] {ex.Message}"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |