Sic04/FrameworkLocal/RTEquipmentLibrary/HardwareUnits/Efems/Rorzes/SocketClient.cs

352 lines
10 KiB
C#
Raw Normal View History

2022-09-19 09:16:33 +08:00
using System;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using Aitex.Core.RT.Log;
using MECF.Framework.Common.Communications;
namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Efems.Rorzes
{
public class SocketClient : IDisposable, IConnectable
{
public class ClientStateObject
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public static int BufferSize = 256;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
public ClientStateObject(int bufferSize = 256)
{
BufferSize = bufferSize;
buffer = new byte[bufferSize];
}
}
public event Action<string> OnCommunicationError;
public event Action<string> OnAsciiDataReceived;
public event Action<byte[]> OnBinaryDataReceived;
public bool IsConnected { get { return (_socket != null && _socket.Connected); } }
private Socket _socket;
private int _bufferSize = 256;
private static Object _lockerSocket = new Object();
private IConnectionContext _config;
public SocketClient(IConnectionContext config)
{
_config = config;
}
~SocketClient()
{
Dispose();
}
public void Connect()
{
try
{
string ip = _config.Address.Split(':')[0];
int port = int.Parse(_config.Address.Split(':')[1]);
IPAddress ipAddress = IPAddress.Parse(ip);
IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
lock (_lockerSocket)
{
Dispose();
if (_socket == null)
{
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
_socket.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), _socket);
}
}
catch (Exception ex)
{
LOG.Error($"Failed connect, " + ex);
}
}
private void ConnectCallback(IAsyncResult ar)
{
try
{
Socket client = (Socket)ar.AsyncState;
if (client.Connected)
{
client.EndConnect(ar);
ClientStateObject state = new ClientStateObject(_bufferSize);
state.workSocket = _socket;
_socket.BeginReceive(state.buffer, 0, ClientStateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
}
catch (Exception ex)
{
LOG.Error($"Failed connect, " + ex);
}
}
public bool Connect(out string reason)
{
Connect( );
reason = string.Empty;
return true;
}
public bool Disconnect(out string reason)
{
Dispose();
reason = string.Empty;
return true;
}
public bool CheckIsConnected()
{
if (!IsConnected)
return false;
lock (_lockerSocket)
{
if ((_socket.Poll(0, SelectMode.SelectWrite)) && (!_socket.Poll(0, SelectMode.SelectError)))
{
//byte[] buffer = new byte[1];
//_socket.ReceiveTimeout
//if (_socket.Receive(buffer, SocketFlags.Peek) == 0)
//{
// return false;
//}
//else
//{
return true;
//}
}
else
{
return false;
}
}
}
public bool SendBinaryData(byte[] data)
{
try
{
lock (_lockerSocket)
{
_socket.BeginSend(data, 0, data.Length, 0, new AsyncCallback(SendCallback), _socket);
if (_config.EnableLog)
{
LOG.Info($"Communication {_config.Address} Send {string.Join(" ", data)}." );
}
}
return true;
}
catch (Exception ex)
{
LOG.Info($"Failed send {string.Join(" ", data)}, " + ex);
NotifyError(ex.Message);
}
return false;
}
public bool SendAsciiData(string data)
{
try
{
lock (_lockerSocket)
{
byte[] byteData = Encoding.ASCII.GetBytes(data);
_socket.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), _socket);
if (_config.EnableLog)
{
LOG.Info($"Communication {_config.Address} Send {string.Join(" ", data)}.");
}
}
return true;
}
catch (Exception ex)
{
LOG.Info($"Failed send {string.Join(" ", data)}, " + ex);
NotifyError(ex.Message);
}
return false;
}
private void ReceiveCallback(IAsyncResult ar)
{
try
{
if (!IsConnected)
{
return;
}
ClientStateObject state = (ClientStateObject)ar.AsyncState;
Socket client = state.workSocket;
int bytesRead = client.EndReceive(ar);
if (bytesRead > 0)
{
string receiveMessage = Encoding.ASCII.GetString(state.buffer, 0, bytesRead);
state.sb.Append(receiveMessage);
if (!_config.IsAscii)
{
byte[] recvBuff = new byte[bytesRead];
for (int i = 0; i < bytesRead; i++)
{
recvBuff[i] = state.buffer[i];
}
if (_config.EnableLog)
{
LOG.Info($"Communication {_config.Address} receive {string.Join(" ", recvBuff)}.");
}
if (OnBinaryDataReceived != null)
{
OnBinaryDataReceived(recvBuff);
}
state.sb.Clear();
}
else if (state.sb.Length > _config.NewLine.Length)
{
if (state.sb.ToString().Substring(state.sb.Length - _config.NewLine.Length).Equals(_config.NewLine))
{
string msg = state.sb.ToString();
if (_config.EnableLog)
{
LOG.Info($"Communication {_config.Address} receive {msg}.");
}
if (OnAsciiDataReceived != null)
{
OnAsciiDataReceived(state.sb.ToString());
}
state.sb.Clear();
}
}
// Get the rest of the data.
client.BeginReceive(state.buffer, 0, ClientStateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
}
catch (Exception ex)
{
LOG.Info($"Failed receive data, " + ex);
NotifyError(ex.Message);
}
}
private void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = client.EndSend(ar);
}
catch (Exception ex)
{
LOG.Info($"Failed send data, " + ex);
NotifyError(ex.Message);
}
}
/// <summary>
/// 释放资源Dispose
/// </summary>
public void Dispose()
{
try
{
if (_socket != null)
{
if (IsConnected)
{
_socket.Shutdown(SocketShutdown.Both);
}
_socket.Close();
_socket.Dispose();
_socket = null;
}
}
catch (Exception ex)
{
LOG.Write($"Dispose {_config.Address} resource exception, {ex}");
}
}
private void NotifyError(string reason)
{
if (OnCommunicationError != null)
OnCommunicationError(reason);
}
private bool PingConnect()
{
bool result = true;
if (_socket != null && _socket.Connected)
{
try
{
Ping pingTest = new Ping();
PingReply reply = pingTest.Send(_config.Address.Split(':')[0]);
if (reply.Status != IPStatus.Success)
result = false;
}
catch (PingException) { result = false; }
if (_socket.Poll(1000, SelectMode.SelectRead) && (_socket.Available == 0))
{
result = false;
}
}
else
{
result = false;
}
return result;
}
}
}