mirror of
https://github.com/S7NetPlus/s7netplus.git
synced 2026-02-17 14:28:25 +08:00
481 lines
15 KiB
C#
481 lines
15 KiB
C#
using System;
|
|
using System.Net.Sockets;
|
|
using System.Threading;
|
|
using System.Net;
|
|
|
|
namespace S7.Net
|
|
{
|
|
/// <summary>
|
|
/// This class encapsulate System.Net.Sockets.Socket class of .Net core, so we can use the same methods of the standard Socket class inside the S7.Net sources.
|
|
/// </summary>
|
|
internal class Socket
|
|
{
|
|
|
|
public bool Connected
|
|
{
|
|
get
|
|
{
|
|
if (_socket == null)
|
|
return false;
|
|
|
|
return _socket.Connected;
|
|
}
|
|
}
|
|
|
|
public SocketError LastSocketError { get; private set; }
|
|
|
|
public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
|
|
{
|
|
_socket = new System.Net.Sockets.Socket(addressFamily, socketType, protocolType);
|
|
}
|
|
|
|
public void Connect(IPEndPoint server)
|
|
{
|
|
if (Connected)
|
|
return;
|
|
|
|
LastSocketError = SocketError.NotConnected;
|
|
|
|
var socketEventArg = new SocketAsyncEventArgs();
|
|
|
|
socketEventArg.RemoteEndPoint = server;
|
|
|
|
var completedEvent = new EventHandler<SocketAsyncEventArgs>(delegate (object s, SocketAsyncEventArgs e)
|
|
{
|
|
LastSocketError = e.SocketError;
|
|
_clientDone.Set();
|
|
});
|
|
|
|
socketEventArg.Completed += completedEvent;
|
|
|
|
_clientDone.Reset();
|
|
|
|
LastSocketError = SocketError.TimedOut;
|
|
|
|
_socket.ConnectAsync(socketEventArg);
|
|
|
|
_clientDone.WaitOne(TIMEOUT_MILLISECONDS);
|
|
|
|
socketEventArg.Completed -= completedEvent;
|
|
}
|
|
|
|
public int Send(byte[] buffer, int size, SocketFlags socketFlag)
|
|
{
|
|
var response = 0;
|
|
|
|
if (_socket != null)
|
|
{
|
|
var socketEventArg = new SocketAsyncEventArgs();
|
|
|
|
socketEventArg.RemoteEndPoint = _socket.RemoteEndPoint;
|
|
socketEventArg.UserToken = null;
|
|
|
|
var completedEvent = new EventHandler<SocketAsyncEventArgs>(delegate (object s, SocketAsyncEventArgs e)
|
|
{
|
|
LastSocketError = e.SocketError;
|
|
|
|
if (e.SocketError == SocketError.Success)
|
|
response = e.BytesTransferred;
|
|
|
|
_clientDone.Set();
|
|
});
|
|
|
|
socketEventArg.Completed += completedEvent;
|
|
|
|
socketEventArg.SetBuffer(buffer, 0, size);
|
|
|
|
_clientDone.Reset();
|
|
|
|
LastSocketError = SocketError.TimedOut;
|
|
|
|
_socket.SendAsync(socketEventArg);
|
|
|
|
_clientDone.WaitOne(_sendTimeout);
|
|
|
|
socketEventArg.Completed -= completedEvent;
|
|
}
|
|
else
|
|
{
|
|
LastSocketError = SocketError.NotInitialized;
|
|
}
|
|
|
|
return response;
|
|
}
|
|
|
|
public int Receive(byte[] buffer, int size, SocketFlags socketFlag)
|
|
{
|
|
var response = 0;
|
|
|
|
if (_socket != null)
|
|
{
|
|
var socketEventArg = new SocketAsyncEventArgs();
|
|
|
|
socketEventArg.RemoteEndPoint = _socket.RemoteEndPoint;
|
|
socketEventArg.SetBuffer(buffer, 0, size);
|
|
|
|
var completedEvent = new EventHandler<SocketAsyncEventArgs>(delegate (object s, SocketAsyncEventArgs e)
|
|
{
|
|
LastSocketError = e.SocketError;
|
|
|
|
if (e.SocketError == SocketError.Success)
|
|
response = e.BytesTransferred;
|
|
|
|
_clientDone.Set();
|
|
});
|
|
|
|
socketEventArg.Completed += completedEvent;
|
|
|
|
_clientDone.Reset();
|
|
|
|
LastSocketError = SocketError.TimedOut;
|
|
|
|
_socket.ReceiveAsync(socketEventArg);
|
|
|
|
_clientDone.WaitOne(_receiveTimeout);
|
|
|
|
socketEventArg.Completed -= completedEvent;
|
|
}
|
|
else
|
|
{
|
|
LastSocketError = SocketError.NotInitialized;
|
|
}
|
|
|
|
return response;
|
|
}
|
|
|
|
public void Shutdown(SocketShutdown how)
|
|
{
|
|
_socket.Shutdown(how);
|
|
}
|
|
|
|
public void Close()
|
|
{
|
|
if (_socket != null)
|
|
{
|
|
_socket.Dispose();
|
|
_socket = null;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Summary:
|
|
// Sets the specified System.Net.Sockets.Socket option to the specified integer
|
|
// value.
|
|
//
|
|
// Parameters:
|
|
// optionLevel:
|
|
// One of the System.Net.Sockets.SocketOptionLevel values.
|
|
//
|
|
// optionName:
|
|
// One of the System.Net.Sockets.SocketOptionName values.
|
|
//
|
|
// optionValue:
|
|
// A value of the option.
|
|
//
|
|
// Exceptions:
|
|
// T:System.Net.Sockets.SocketException:
|
|
// An error occurred when attempting to access the socket. See the Remarks section
|
|
// for more information.
|
|
//
|
|
// T:System.ObjectDisposedException:
|
|
// The System.Net.Sockets.Socket has been closed.
|
|
public void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
|
|
{
|
|
switch (optionName)
|
|
{
|
|
case SocketOptionName.ReceiveTimeout:
|
|
_receiveTimeout = optionValue;
|
|
break;
|
|
|
|
case SocketOptionName.SendTimeout:
|
|
_sendTimeout = optionValue;
|
|
break;
|
|
|
|
default:
|
|
throw new NotImplementedException("SetSocketOption option not implemented");
|
|
}
|
|
}
|
|
|
|
private System.Net.Sockets.Socket _socket = null;
|
|
private int _receiveTimeout = TIMEOUT_MILLISECONDS;
|
|
private int _sendTimeout = TIMEOUT_MILLISECONDS;
|
|
|
|
private readonly static ManualResetEvent _clientDone =
|
|
new ManualResetEvent(false);
|
|
|
|
private const int TIMEOUT_MILLISECONDS = 1000;
|
|
|
|
}
|
|
|
|
//
|
|
// Summary:
|
|
// Specifies socket send and receive behaviors.
|
|
[Flags]
|
|
public enum SocketFlags
|
|
{
|
|
//
|
|
// Summary:
|
|
// Use no flags for this call.
|
|
None = 0,
|
|
////
|
|
//// Summary:
|
|
//// Process out-of-band data.
|
|
//OutOfBand = 1,
|
|
////
|
|
//// Summary:
|
|
//// Peek at the incoming message.
|
|
//Peek = 2,
|
|
////
|
|
//// Summary:
|
|
//// Send without using routing tables.
|
|
//DontRoute = 4,
|
|
////
|
|
//// Summary:
|
|
//// Provides a standard value for the number of WSABUF structures that are used to
|
|
//// send and receive data.
|
|
//MaxIOVectorLength = 16,
|
|
////
|
|
//// Summary:
|
|
//// The message was too large to fit into the specified buffer and was truncated.
|
|
//Truncated = 256,
|
|
////
|
|
//// Summary:
|
|
//// Indicates that the control data did not fit into an internal 64-KB buffer and
|
|
//// was truncated.
|
|
//ControlDataTruncated = 512,
|
|
////
|
|
//// Summary:
|
|
//// Indicates a broadcast packet.
|
|
//Broadcast = 1024,
|
|
////
|
|
//// Summary:
|
|
//// Indicates a multicast packet.
|
|
//Multicast = 2048,
|
|
////
|
|
//// Summary:
|
|
//// Partial send or receive for message.
|
|
//Partial = 32768
|
|
}
|
|
|
|
//
|
|
// Summary:
|
|
// Defines socket option levels for the System.Net.Sockets.Socket.SetSocketOption(System.Net.Sockets.SocketOptionLevel,System.Net.Sockets.SocketOptionName,System.Int32)
|
|
// and System.Net.Sockets.Socket.GetSocketOption(System.Net.Sockets.SocketOptionLevel,System.Net.Sockets.SocketOptionName)
|
|
// methods.
|
|
public enum SocketOptionLevel
|
|
{
|
|
//
|
|
// Summary:
|
|
// System.Net.Sockets.Socket options apply only to IP sockets.
|
|
IP = 0,
|
|
//
|
|
// Summary:
|
|
// System.Net.Sockets.Socket options apply only to TCP sockets.
|
|
Tcp = 6,
|
|
//
|
|
// Summary:
|
|
// System.Net.Sockets.Socket options apply only to UDP sockets.
|
|
Udp = 17,
|
|
//
|
|
// Summary:
|
|
// System.Net.Sockets.Socket options apply only to IPv6 sockets.
|
|
IPv6 = 41,
|
|
//
|
|
// Summary:
|
|
// System.Net.Sockets.Socket options apply to all sockets.
|
|
Socket = 65535
|
|
}
|
|
|
|
//
|
|
// Summary:
|
|
// Defines configuration option names.
|
|
public enum SocketOptionName
|
|
{
|
|
//
|
|
// Summary:
|
|
// Close the socket gracefully without lingering.
|
|
DontLinger = -129,
|
|
//
|
|
// Summary:
|
|
// Enables a socket to be bound for exclusive access.
|
|
ExclusiveAddressUse = -5,
|
|
//
|
|
// Summary:
|
|
// Record debugging information.
|
|
Debug = 1,
|
|
//
|
|
// Summary:
|
|
// Specifies the IP options to be inserted into outgoing datagrams.
|
|
IPOptions = 1,
|
|
//
|
|
// Summary:
|
|
// Disables the Nagle algorithm for send coalescing.
|
|
NoDelay = 1,
|
|
//
|
|
// Summary:
|
|
// Send UDP datagrams with checksum set to zero.
|
|
NoChecksum = 1,
|
|
//
|
|
// Summary:
|
|
// The socket is listening.
|
|
AcceptConnection = 2,
|
|
//
|
|
// Summary:
|
|
// Indicates that the application provides the IP header for outgoing datagrams.
|
|
HeaderIncluded = 2,
|
|
//
|
|
// Summary:
|
|
// Use urgent data as defined in RFC-1222. This option can be set only once; after
|
|
// it is set, it cannot be turned off.
|
|
BsdUrgent = 2,
|
|
//
|
|
// Summary:
|
|
// Use expedited data as defined in RFC-1222. This option can be set only once;
|
|
// after it is set, it cannot be turned off.
|
|
Expedited = 2,
|
|
//
|
|
// Summary:
|
|
// Change the IP header type of the service field.
|
|
TypeOfService = 3,
|
|
//
|
|
// Summary:
|
|
// Allows the socket to be bound to an address that is already in use.
|
|
ReuseAddress = 4,
|
|
//
|
|
// Summary:
|
|
// Set the IP header Time-to-Live field.
|
|
IpTimeToLive = 4,
|
|
//
|
|
// Summary:
|
|
// Use keep-alives.
|
|
KeepAlive = 8,
|
|
//
|
|
// Summary:
|
|
// Set the interface for outgoing multicast packets.
|
|
MulticastInterface = 9,
|
|
//
|
|
// Summary:
|
|
// An IP multicast Time to Live.
|
|
MulticastTimeToLive = 10,
|
|
//
|
|
// Summary:
|
|
// An IP multicast loopback.
|
|
MulticastLoopback = 11,
|
|
//
|
|
// Summary:
|
|
// Add an IP group membership.
|
|
AddMembership = 12,
|
|
//
|
|
// Summary:
|
|
// Drop an IP group membership.
|
|
DropMembership = 13,
|
|
//
|
|
// Summary:
|
|
// Do not fragment IP datagrams.
|
|
DontFragment = 14,
|
|
//
|
|
// Summary:
|
|
// Join a source group.
|
|
AddSourceMembership = 15,
|
|
//
|
|
// Summary:
|
|
// Do not route; send the packet directly to the interface addresses.
|
|
DontRoute = 16,
|
|
//
|
|
// Summary:
|
|
// Drop a source group.
|
|
DropSourceMembership = 16,
|
|
//
|
|
// Summary:
|
|
// Block data from a source.
|
|
BlockSource = 17,
|
|
//
|
|
// Summary:
|
|
// Unblock a previously blocked source.
|
|
UnblockSource = 18,
|
|
//
|
|
// Summary:
|
|
// Return information about received packets.
|
|
PacketInformation = 19,
|
|
//
|
|
// Summary:
|
|
// Set or get the UDP checksum coverage.
|
|
ChecksumCoverage = 20,
|
|
//
|
|
// Summary:
|
|
// Specifies the maximum number of router hops for an Internet Protocol version
|
|
// 6 (IPv6) packet. This is similar to Time to Live (TTL) for Internet Protocol
|
|
// version 4.
|
|
HopLimit = 21,
|
|
//
|
|
// Summary:
|
|
// Permit sending broadcast messages on the socket.
|
|
Broadcast = 32,
|
|
//
|
|
// Summary:
|
|
// Bypass hardware when possible.
|
|
UseLoopback = 64,
|
|
//
|
|
// Summary:
|
|
// Linger on close if unsent data is present.
|
|
Linger = 128,
|
|
//
|
|
// Summary:
|
|
// Receives out-of-band data in the normal data stream.
|
|
OutOfBandInline = 256,
|
|
//
|
|
// Summary:
|
|
// Specifies the total per-socket buffer space reserved for sends. This is unrelated
|
|
// to the maximum message size or the size of a TCP window.
|
|
SendBuffer = 4097,
|
|
//
|
|
// Summary:
|
|
// Specifies the total per-socket buffer space reserved for receives. This is unrelated
|
|
// to the maximum message size or the size of a TCP window.
|
|
ReceiveBuffer = 4098,
|
|
//
|
|
// Summary:
|
|
// Specifies the low water mark for Overload:System.Net.Sockets.Socket.Send operations.
|
|
SendLowWater = 4099,
|
|
//
|
|
// Summary:
|
|
// Specifies the low water mark for Overload:System.Net.Sockets.Socket.Receive operations.
|
|
ReceiveLowWater = 4100,
|
|
//
|
|
// Summary:
|
|
// Send a time-out. This option applies only to synchronous methods; it has no effect
|
|
// on asynchronous methods such as the System.Net.Sockets.Socket.BeginSend(System.Byte[],System.Int32,System.Int32,System.Net.Sockets.SocketFlags,System.AsyncCallback,System.Object)
|
|
// method.
|
|
SendTimeout = 4101,
|
|
//
|
|
// Summary:
|
|
// Receive a time-out. This option applies only to synchronous methods; it has no
|
|
// effect on asynchronous methods such as the System.Net.Sockets.Socket.BeginSend(System.Byte[],System.Int32,System.Int32,System.Net.Sockets.SocketFlags,System.AsyncCallback,System.Object)
|
|
// method.
|
|
ReceiveTimeout = 4102,
|
|
//
|
|
// Summary:
|
|
// Get the error status and clear.
|
|
Error = 4103,
|
|
//
|
|
// Summary:
|
|
// Get the socket type.
|
|
Type = 4104,
|
|
//
|
|
// Summary:
|
|
// Updates an accepted socket's properties by using those of an existing socket.
|
|
// This is equivalent to using the Winsock2 SO_UPDATE_ACCEPT_CONTEXT socket option
|
|
// and is supported only on connection-oriented sockets.
|
|
UpdateAcceptContext = 28683,
|
|
//
|
|
// Summary:
|
|
// Updates a connected socket's properties by using those of an existing socket.
|
|
// This is equivalent to using the Winsock2 SO_UPDATE_CONNECT_CONTEXT socket option
|
|
// and is supported only on connection-oriented sockets.
|
|
UpdateConnectContext = 28688,
|
|
//
|
|
// Summary:
|
|
// Not supported; will throw a System.Net.Sockets.SocketException if used.
|
|
MaxConnections = int.MaxValue
|
|
}
|
|
} |