352 lines
10 KiB
C#
352 lines
10 KiB
C#
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;
|
||
}
|
||
}
|
||
|
||
|
||
}
|