Dreamine.IO.Fastech.Ethernet
1.0.1
Dreamine.IO.Fastech.Ethernet 산업 자동화 및 I/O 기능을 제공합니다.
Toggle main menu visibility
로딩중...
검색중...
일치하는것 없음
UdpFastechEthernetIoTransport.cs
이 파일의 문서화 페이지로 가기
1
using
System.Net;
2
using
System.Net.Sockets;
3
using
Dreamine.IO.Abstractions.Results;
4
using
Dreamine.IO.Fastech.Ethernet.Options
;
5
6
namespace
Dreamine.IO.Fastech.Ethernet.Transport
;
7
16
public
sealed
class
UdpFastechEthernetIoTransport
:
IFastechEthernetIoTransport
17
{
26
private
readonly SemaphoreSlim
_syncLock
=
new
(1, 1);
35
private
readonly
FastechEthernetIoOptions
_options
;
44
private
UdpClient?
_udpClient
;
53
private
IPEndPoint?
_remoteEndPoint
;
62
private
bool
_disposed
;
63
88
public
UdpFastechEthernetIoTransport
(
FastechEthernetIoOptions
options)
89
{
90
_options
= options ??
throw
new
ArgumentNullException(nameof(options));
91
}
92
101
public
bool
IsConnected
=>
_udpClient
is not
null
;
102
111
public
byte
[]
LastRequestFrame
{
get
;
private
set
; } = [];
112
121
public
byte
[]
LastResponseFrame
{
get
;
private
set
; } = [];
122
155
public
async Task<IoResult>
ConnectAsync
(CancellationToken cancellationToken =
default
)
156
{
157
if
(
string
.IsNullOrWhiteSpace(
_options
.Host))
158
{
159
return
IoResult.Failure(
"The Fastech host must not be empty."
);
160
}
161
162
if
(
_options
.Port is <= 0 or > 65535)
163
{
164
return
IoResult.Failure($
"Invalid UDP port: {_options.Port}."
);
165
}
166
167
if
(
_options
.LocalPort is < 0 or > 65535)
168
{
169
return
IoResult.Failure($
"Invalid local UDP port: {_options.LocalPort}."
);
170
}
171
172
await
_syncLock
.WaitAsync(cancellationToken).ConfigureAwait(
false
);
173
174
try
175
{
176
ThrowIfDisposed
();
177
178
if
(
IsConnected
)
179
{
180
return
IoResult.Success();
181
}
182
183
var remoteAddress = await
ResolveRemoteAddressAsync
(cancellationToken).ConfigureAwait(
false
);
184
_remoteEndPoint
=
new
IPEndPoint(remoteAddress,
_options
.Port);
185
_udpClient
= _options.LocalPort == 0
186
?
new
UdpClient(remoteAddress.AddressFamily)
187
:
new
UdpClient(
_options
.LocalPort, remoteAddress.AddressFamily);
188
189
DisableUdpConnectionReset
(
_udpClient
);
190
191
return
IoResult.Success();
192
}
193
catch
(Exception ex)
194
{
195
await
CloseCoreAsync
().ConfigureAwait(
false
);
196
return
IoResult.Failure(ex.Message);
197
}
198
finally
199
{
200
_syncLock
.Release();
201
}
202
}
203
236
public
async Task<IoResult>
DisconnectAsync
(CancellationToken cancellationToken =
default
)
237
{
238
await
_syncLock
.WaitAsync(cancellationToken).ConfigureAwait(
false
);
239
240
try
241
{
242
await
CloseCoreAsync
().ConfigureAwait(
false
);
243
return
IoResult.Success();
244
}
245
catch
(Exception ex)
246
{
247
return
IoResult.Failure(ex.Message);
248
}
249
finally
250
{
251
_syncLock
.Release();
252
}
253
}
254
319
public
async Task<IoResult<byte[]>>
SendAndReceiveAsync
(
320
IReadOnlyList<byte> requestFrame,
321
int
receiveTimeoutMs,
322
int
expectedResponseLength,
323
CancellationToken cancellationToken =
default
)
324
{
325
ArgumentNullException.ThrowIfNull(requestFrame);
326
327
if
(requestFrame.Count == 0)
328
{
329
return
IoResult<byte[]>.Failure(
"The request frame must not be empty."
);
330
}
331
332
if
(receiveTimeoutMs <= 0)
333
{
334
return
IoResult<byte[]>.Failure(
"The receive timeout must be greater than zero."
);
335
}
336
337
await
_syncLock
.WaitAsync(cancellationToken).ConfigureAwait(
false
);
338
339
try
340
{
341
ThrowIfDisposed
();
342
343
if
(
_udpClient
is
null
||
_remoteEndPoint
is
null
)
344
{
345
return
IoResult<byte[]>.Failure(
"The Fastech UDP transport is not connected."
);
346
}
347
348
var requestBuffer = requestFrame as
byte
[] ?? requestFrame.ToArray();
349
LastRequestFrame
= requestBuffer;
350
LastResponseFrame
= [];
351
352
using
var timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
353
timeoutCts.CancelAfter(receiveTimeoutMs);
354
355
await
_udpClient
.SendAsync(requestBuffer,
_remoteEndPoint
, timeoutCts.Token).ConfigureAwait(
false
);
356
var response = await
_udpClient
.ReceiveAsync(timeoutCts.Token).ConfigureAwait(
false
);
357
LastResponseFrame
= response.Buffer;
358
359
return
IoResult<byte[]>.Success(response.Buffer);
360
}
361
catch
(OperationCanceledException ex)
362
{
363
return
IoResult<byte[]>.Failure($
"No UDP response from {_options.Host}:{_options.Port} within {receiveTimeoutMs} ms. {ex.Message}"
);
364
}
365
catch
(SocketException ex) when (ex.SocketErrorCode == SocketError.ConnectionReset)
366
{
367
return
IoResult<byte[]>.Failure(
368
$
"No UDP listener responded at {_options.Host}:{_options.Port}. Windows reported UDP reset/ICMP port unreachable. {ex.Message}"
);
369
}
370
catch
(Exception ex)
371
{
372
return
IoResult<byte[]>.Failure(ex.Message);
373
}
374
finally
375
{
376
_syncLock
.Release();
377
}
378
}
379
396
public
async ValueTask
DisposeAsync
()
397
{
398
if
(
_disposed
)
399
{
400
return
;
401
}
402
403
await
DisconnectAsync
().ConfigureAwait(
false
);
404
_syncLock
.Dispose();
405
_disposed
=
true
;
406
407
GC.SuppressFinalize(
this
);
408
}
409
426
private
Task
CloseCoreAsync
()
427
{
428
_udpClient
?.Dispose();
429
_udpClient
=
null
;
430
_remoteEndPoint
=
null
;
431
432
return
Task.CompletedTask;
433
}
434
467
private
async Task<IPAddress>
ResolveRemoteAddressAsync
(CancellationToken cancellationToken)
468
{
469
if
(IPAddress.TryParse(
_options
.Host, out var address))
470
{
471
return
address;
472
}
473
474
var addresses = await Dns.GetHostAddressesAsync(
_options
.Host, cancellationToken).ConfigureAwait(
false
);
475
var resolvedAddress = addresses.FirstOrDefault(x => x.AddressFamily == AddressFamily.InterNetwork)
476
?? addresses.FirstOrDefault();
477
478
return
resolvedAddress ??
throw
new
InvalidOperationException($
"Unable to resolve UDP host: {_options.Host}."
);
479
}
480
497
private
static
void
DisableUdpConnectionReset
(UdpClient client)
498
{
499
if
(!OperatingSystem.IsWindows())
500
{
501
return
;
502
}
503
504
try
505
{
506
const
int
sioUdpConnReset = -1744830452;
507
client.Client.IOControl(sioUdpConnReset, [0],
null
);
508
}
509
catch
(SocketException)
510
{
511
}
512
}
513
530
private
void
ThrowIfDisposed
()
531
{
532
ObjectDisposedException.ThrowIf(
_disposed
,
this
);
533
}
534
}
Dreamine.IO.Fastech.Ethernet.Options
Definition
FastechEthernetIoOptions.cs:4
Dreamine.IO.Fastech.Ethernet.Transport
Definition
IFastechEthernetIoTransport.cs:3
Dreamine.IO.Fastech.Ethernet.Options.FastechEthernetIoOptions
Definition
FastechEthernetIoOptions.cs:15
Dreamine.IO.Fastech.Ethernet.Transport.IFastechEthernetIoTransport
Definition
IFastechEthernetIoTransport.cs:14
Dreamine.IO.Fastech.Ethernet.Transport.UdpFastechEthernetIoTransport.SendAndReceiveAsync
async Task< IoResult< byte[]> > SendAndReceiveAsync(IReadOnlyList< byte > requestFrame, int receiveTimeoutMs, int expectedResponseLength, CancellationToken cancellationToken=default)
Definition
UdpFastechEthernetIoTransport.cs:319
Dreamine.IO.Fastech.Ethernet.Transport.UdpFastechEthernetIoTransport.ConnectAsync
async Task< IoResult > ConnectAsync(CancellationToken cancellationToken=default)
Definition
UdpFastechEthernetIoTransport.cs:155
Dreamine.IO.Fastech.Ethernet.Transport.UdpFastechEthernetIoTransport.LastRequestFrame
byte[] LastRequestFrame
Definition
UdpFastechEthernetIoTransport.cs:111
Dreamine.IO.Fastech.Ethernet.Transport.UdpFastechEthernetIoTransport.ThrowIfDisposed
void ThrowIfDisposed()
Definition
UdpFastechEthernetIoTransport.cs:530
Dreamine.IO.Fastech.Ethernet.Transport.UdpFastechEthernetIoTransport._options
readonly FastechEthernetIoOptions _options
Definition
UdpFastechEthernetIoTransport.cs:35
Dreamine.IO.Fastech.Ethernet.Transport.UdpFastechEthernetIoTransport.DisconnectAsync
async Task< IoResult > DisconnectAsync(CancellationToken cancellationToken=default)
Definition
UdpFastechEthernetIoTransport.cs:236
Dreamine.IO.Fastech.Ethernet.Transport.UdpFastechEthernetIoTransport.IsConnected
bool IsConnected
Definition
UdpFastechEthernetIoTransport.cs:101
Dreamine.IO.Fastech.Ethernet.Transport.UdpFastechEthernetIoTransport._remoteEndPoint
IPEndPoint? _remoteEndPoint
Definition
UdpFastechEthernetIoTransport.cs:53
Dreamine.IO.Fastech.Ethernet.Transport.UdpFastechEthernetIoTransport._disposed
bool _disposed
Definition
UdpFastechEthernetIoTransport.cs:62
Dreamine.IO.Fastech.Ethernet.Transport.UdpFastechEthernetIoTransport._syncLock
readonly SemaphoreSlim _syncLock
Definition
UdpFastechEthernetIoTransport.cs:26
Dreamine.IO.Fastech.Ethernet.Transport.UdpFastechEthernetIoTransport.DisposeAsync
async ValueTask DisposeAsync()
Definition
UdpFastechEthernetIoTransport.cs:396
Dreamine.IO.Fastech.Ethernet.Transport.UdpFastechEthernetIoTransport.DisableUdpConnectionReset
static void DisableUdpConnectionReset(UdpClient client)
Definition
UdpFastechEthernetIoTransport.cs:497
Dreamine.IO.Fastech.Ethernet.Transport.UdpFastechEthernetIoTransport.LastResponseFrame
byte[] LastResponseFrame
Definition
UdpFastechEthernetIoTransport.cs:121
Dreamine.IO.Fastech.Ethernet.Transport.UdpFastechEthernetIoTransport.ResolveRemoteAddressAsync
async Task< IPAddress > ResolveRemoteAddressAsync(CancellationToken cancellationToken)
Definition
UdpFastechEthernetIoTransport.cs:467
Dreamine.IO.Fastech.Ethernet.Transport.UdpFastechEthernetIoTransport._udpClient
UdpClient? _udpClient
Definition
UdpFastechEthernetIoTransport.cs:44
Dreamine.IO.Fastech.Ethernet.Transport.UdpFastechEthernetIoTransport.UdpFastechEthernetIoTransport
UdpFastechEthernetIoTransport(FastechEthernetIoOptions options)
Definition
UdpFastechEthernetIoTransport.cs:88
Dreamine.IO.Fastech.Ethernet.Transport.UdpFastechEthernetIoTransport.CloseCoreAsync
Task CloseCoreAsync()
Definition
UdpFastechEthernetIoTransport.cs:426
Transport
UdpFastechEthernetIoTransport.cs
다음에 의해 생성됨 :
1.17.0