using System;
using System.Net.Sockets;
using Curtain.Net.Sockets.PLC.ThreadLock;
namespace Curtain.Net.Sockets.PLC
{
///
/// Socket 通信基类
///
public abstract class PLCSocket : IDisposable
{
#region 变量
#endregion
#region 属性
///
/// 销毁状态
///
public bool IsDispose
{
get;
protected set;
}
///
/// 通信用Socket
///
public Socket Socket
{
get; protected set;
}
///
/// 线程锁
///
public IThreadLock ThreadLock
{
get;
protected set;
} = new ReaderWriterThreadLock();
#endregion
#region 构造
///
/// Socket 通信基类
///
public PLCSocket()
{
}
///
/// Socket 通信基类
///
/// Socket
public PLCSocket(Socket socket)
{
this.Socket = socket;
}
#endregion
#region 连接&关闭
///
/// 创建Socket
///
///
///
///
public virtual void CreateSocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
{
if (Socket != null)
{
try
{
//if (Socket.Connected)
//{
// Socket.Close();
//}
Socket.Dispose();
}
catch
{
}
}
if (IsDispose)
{
IsDispose = false;
}
if (ThreadLock == null)
{
ThreadLock = new ReaderWriterThreadLock();
}
Socket = new Socket(addressFamily, socketType, protocolType);
}
///
/// 创建Socket
///
public virtual void CreateSocket()
{
CreateSocket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
///
/// 连接Socket
///
///
///
public virtual void Connect(string host, int port)
{
if (this.Socket == null)
{
this.CreateSocket();
}
//else
//{
// // 刷新 Connected 状态(服务端关闭连接时,客户端 Connected=true)。
// try
// {
// bool b = Socket.EnableBroadcast;
// }
// catch
// {
// }
//}
if (!this.Socket.Connected)
{
try
{
this.Socket.Connect(host, port);
this.OnSocketConnect();
}
//catch (InvalidOperationException ex)
catch //(Exception ex)
{
this.Close();
this.CreateSocket();
this.Socket.Connect(host, port);
this.OnSocketConnect();
}
}
}
///
/// Socket连接后PLC初始化
///
public virtual void OnSocketConnect()
{
}
///
/// 断开连接
///
public virtual void Disconnect()
{
if (this.Socket == null)
{
return;
}
if (this.Socket.Connected)
{
try
{
this.Socket.Disconnect(true);
}
catch //(Exception ex)
{
this.Close();
this.Socket = null;
}
}
}
///
/// 关闭Socket
///
///
public virtual bool Close()
{
if (Socket == null)
{
return true;
}
try
{
Socket.Close();
Socket = null;
}
catch //(Exception ex)
{
return false;
}
return true;
}
///
/// 销毁
///
public virtual void Dispose()
{
try
{
Socket?.Dispose();
Socket = null;
ThreadLock.Dispose();
ThreadLock = null;
}
catch
{
}
finally
{
IsDispose = true;
}
}
#endregion
#region Send
///
/// 发送
///
///
///
internal protected virtual PLCResult Send(byte[] data)
{
PLCResult plcResult = new PLCResult();
if (data == null || data.Length == 0)
{
plcResult.Successed = false;
plcResult.Message = "no command";
return plcResult;
}
if (Socket == null)
{
plcResult.Successed = false;
plcResult.Message = "no socket";
return plcResult;
}
if (!Socket.Connected)
{
plcResult.Successed = false;
plcResult.Message = "no connected";
return plcResult;
}
try
{
//plcResult.Result = Socket.Send(data);
Socket.Send(data);
}
catch (Exception ex)
{
plcResult.Successed = false;
plcResult.Message = ex.Message;
plcResult.MessageDetail = ex.ToString();
Socket?.Close();
Socket = null;
}
return plcResult;
}
///
/// 异步发送
///
///
///
internal protected virtual PLCResult BeginSend(byte[] data)
{
PLCResult plcResult = new PLCResult();
if (data == null || data.Length == 0)
{
plcResult.Successed = false;
plcResult.Message = "no command";
return plcResult;
}
if (Socket == null)
{
plcResult.Successed = false;
plcResult.Message = "no socket";
return plcResult;
}
if (!Socket.Connected)
{
plcResult.Successed = false;
plcResult.Message = "no connected";
return plcResult;
}
SocketAsyncState sas = new SocketAsyncState();
try
{
sas.Data = data;
sas.Size = data.Length;
sas.Result = plcResult;
Socket.BeginSend(sas.Data, sas.Offset, sas.Size, SocketFlags.None, SendCallBack, sas);
}
catch (Exception ex)
{
plcResult.Successed = false;
plcResult.Message = ex.Message;
plcResult.MessageDetail = ex.ToString();
sas?.Close();
sas = null;
Socket?.Close();
Socket = null;
}
sas?.WaitOne();
sas?.Close();
sas = null;
return plcResult;
}
///
/// 发送结束
///
///
private void SendCallBack(IAsyncResult iar)
{
if (iar.AsyncState is SocketAsyncState sas)
{
try
{
sas.Offset += Socket.EndSend(iar);
if (sas.Offset < sas.Size)
{
Socket.BeginSend(sas.Data, sas.Offset, sas.Size - sas.Offset, SocketFlags.None, SendCallBack, iar);
}
else
{
sas.Set();
}
}
catch (Exception ex)
{
sas.Result.Successed = false;
sas.Result.Message = ex.Message;
sas.Result.MessageDetail = ex.ToString();
Socket.Close();
Socket = null;
sas.Set();
}
}
}
#endregion
#region Receive
///
/// 接收
///
///
///
protected virtual PLCResult Receive(int length)
{
PLCResult plcResult = new PLCResult(new byte[length]);
if (length == 0)
{
plcResult.Successed = false;
plcResult.Message = "no length";
return plcResult;
}
if (Socket == null)
{
plcResult.Successed = false;
plcResult.Message = "no socket";
return plcResult;
}
if (!Socket.Connected)
{
plcResult.Successed = false;
plcResult.Message = "no connected";
return plcResult;
}
try
{
//plcResult.Result = Socket.Receive(plcResult.Data);
//Socket.Receive(plcResult.Data);
Socket.Receive(plcResult.Data, 0, length, SocketFlags.None);
}
catch (Exception ex)
{
plcResult.Successed = false;
plcResult.Message = ex.Message;
plcResult.MessageDetail = ex.ToString();
Socket?.Close();
Socket = null;
}
return plcResult;
}
///
/// 异步接收
///
///
///
protected virtual PLCResult BeginReceive(int length)
{
PLCResult plcResult = new PLCResult(new byte[length]);
if (length == 0)
{
plcResult.Successed = false;
plcResult.Message = "no length";
return plcResult;
}
if (Socket == null)
{
plcResult.Successed = false;
plcResult.Message = "no socket";
return plcResult;
}
if (!Socket.Connected)
{
plcResult.Successed = false;
plcResult.Message = "no connected";
return plcResult;
}
SocketAsyncState sas = new SocketAsyncState();
try
{
sas.Data = plcResult.Data;
sas.Size = length;
sas.Result = plcResult;
Socket.BeginReceive(sas.Data, sas.Offset, sas.Size, SocketFlags.None, ReceiveCallback, sas);
}
catch (Exception ex)
{
plcResult.Successed = false;
plcResult.Message = ex.Message;
plcResult.MessageDetail = ex.ToString();
sas?.Close();
sas = null;
Socket?.Close();
Socket = null;
}
sas?.WaitOne();
sas?.Close();
sas = null;
return plcResult;
}
///
/// 接收结束
///
///
private void ReceiveCallback(IAsyncResult iar)
{
if (iar.AsyncState is SocketAsyncState sas)
{
try
{
int length = Socket.EndReceive(iar);
if (length > 0)
{
sas.Offset += length;
if (sas.Offset < sas.Size)
{
Socket.BeginReceive(sas.Data, sas.Offset, sas.Size - sas.Offset, SocketFlags.None, SendCallBack, iar);
}
else
{
sas.Set();
}
}
else
{
sas.Result.Successed = false;
sas.Result.Message = "other socket has closed";
Socket.Close();
Socket = null;
sas.Set();
}
}
catch (Exception ex)
{
sas.Result.Successed = false;
sas.Result.Message = ex.Message;
sas.Result.MessageDetail = ex.ToString();
Socket.Close();
Socket = null;
sas.Set();
}
}
}
#endregion
}
}