Dreamine.PLC.Mitsubishi.MC
1.0.1
Dreamine.PLC.Mitsubishi.MC 산업 자동화 및 I/O 기능을 제공합니다.
Toggle main menu visibility
로딩중...
검색중...
일치하는것 없음
TcpMitsubishiMcTransport.cs
이 파일의 문서화 페이지로 가기
1
using
System.Net.Sockets;
2
using
Dreamine.PLC.Abstractions.Results;
3
4
namespace
Dreamine.PLC.Mitsubishi.MC.Transport
;
5
14
public
sealed
class
TcpMitsubishiMcTransport
:
IMitsubishiMcTransport
15
{
24
private
readonly SemaphoreSlim
_syncLock
=
new
(1, 1);
33
private
TcpClient?
_tcpClient
;
42
private
NetworkStream?
_stream
;
51
private
bool
_disposed
;
52
61
public
bool
IsConnected
=>
_tcpClient
?.Connected ==
true
&&
_stream
is not
null
;
62
120
public
async Task<PlcResult>
ConnectAsync
(
121
string
host,
122
int
port,
123
int
timeoutMs,
124
CancellationToken cancellationToken =
default
)
125
{
126
ArgumentException.ThrowIfNullOrWhiteSpace(host);
127
128
if
(port is <= 0 or > 65535)
129
{
130
return
PlcResult.Failure($
"Invalid TCP port: {port}"
);
131
}
132
133
if
(timeoutMs <= 0)
134
{
135
return
PlcResult.Failure(
"The connection timeout must be greater than zero."
);
136
}
137
138
await
_syncLock
.WaitAsync(cancellationToken).ConfigureAwait(
false
);
139
140
try
141
{
142
ThrowIfDisposed
();
143
144
if
(
IsConnected
)
145
{
146
return
PlcResult.Success();
147
}
148
149
await
CloseCoreAsync
().ConfigureAwait(
false
);
150
151
_tcpClient
=
new
TcpClient
152
{
153
NoDelay =
true
154
};
155
156
using
var timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
157
timeoutCts.CancelAfter(timeoutMs);
158
159
await
_tcpClient
.ConnectAsync(host, port, timeoutCts.Token).ConfigureAwait(
false
);
160
_stream
=
_tcpClient
.GetStream();
161
162
return
PlcResult.Success();
163
}
164
catch
(OperationCanceledException ex)
165
{
166
await
CloseCoreAsync
().ConfigureAwait(
false
);
167
return
PlcResult.Failure(ex.Message);
168
}
169
catch
(Exception ex)
170
{
171
await
CloseCoreAsync
().ConfigureAwait(
false
);
172
return
PlcResult.Failure(ex.Message);
173
}
174
finally
175
{
176
_syncLock
.Release();
177
}
178
}
179
209
public
async Task<PlcResult>
DisconnectAsync
(CancellationToken cancellationToken =
default
)
210
{
211
await
_syncLock
.WaitAsync(cancellationToken).ConfigureAwait(
false
);
212
213
try
214
{
215
await
CloseCoreAsync
().ConfigureAwait(
false
);
216
return
PlcResult.Success();
217
}
218
catch
(Exception ex)
219
{
220
return
PlcResult.Failure(ex.Message);
221
}
222
finally
223
{
224
_syncLock
.Release();
225
}
226
}
227
285
public
async Task<PlcResult<byte[]>>
SendAndReceiveAsync
(
286
IReadOnlyList<byte> requestFrame,
287
int
receiveTimeoutMs,
288
int
retryCount,
289
CancellationToken cancellationToken =
default
)
290
{
291
ArgumentNullException.ThrowIfNull(requestFrame);
292
293
if
(requestFrame.Count == 0)
294
{
295
return
PlcResult<byte[]>.Failure(
"The request frame must not be empty."
);
296
}
297
298
if
(receiveTimeoutMs <= 0)
299
{
300
return
PlcResult<byte[]>.Failure(
"The receive timeout must be greater than zero."
);
301
}
302
303
await
_syncLock
.WaitAsync(cancellationToken).ConfigureAwait(
false
);
304
305
try
306
{
307
ThrowIfDisposed
();
308
309
if
(
_stream
is
null
||
_tcpClient
is
null
|| !
_tcpClient
.Connected)
310
{
311
return
PlcResult<byte[]>.Failure(
"The TCP transport is not connected."
);
312
}
313
314
var requestBuffer = requestFrame as
byte
[] ?? requestFrame.ToArray();
315
316
using
var timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
317
timeoutCts.CancelAfter(receiveTimeoutMs);
318
319
await
_stream
.WriteAsync(requestBuffer, timeoutCts.Token).ConfigureAwait(
false
);
320
await
_stream
.FlushAsync(timeoutCts.Token).ConfigureAwait(
false
);
321
322
var response = await
ReceiveBinary3EFrameAsync
(
_stream
, timeoutCts.Token).ConfigureAwait(
false
);
323
324
return
PlcResult<byte[]>.Success(response);
325
}
326
catch
(OperationCanceledException ex)
327
{
328
return
PlcResult<byte[]>.Failure(ex.Message);
329
}
330
catch
(Exception ex)
331
{
332
return
PlcResult<byte[]>.Failure(ex.Message);
333
}
334
finally
335
{
336
_syncLock
.Release();
337
}
338
}
339
355
public
async ValueTask
DisposeAsync
()
356
{
357
if
(
_disposed
)
358
{
359
return
;
360
}
361
362
await
DisconnectAsync
().ConfigureAwait(
false
);
363
364
_syncLock
.Dispose();
365
_disposed
=
true
;
366
367
GC.SuppressFinalize(
this
);
368
}
369
413
private
static
async Task<byte[]>
ReceiveBinary3EFrameAsync
(
414
NetworkStream stream,
415
CancellationToken cancellationToken)
416
{
417
var header =
new
byte
[9];
418
419
await
ReadExactlyAsync
(stream, header, cancellationToken).ConfigureAwait(
false
);
420
421
var responseDataLength = header[7] | (header[8] << 8);
422
if
(responseDataLength < 2)
423
{
424
throw
new
InvalidOperationException(
425
$
"Invalid Mitsubishi MC response data length: {responseDataLength}"
);
426
}
427
428
var body =
new
byte
[responseDataLength];
429
430
await
ReadExactlyAsync
(stream, body, cancellationToken).ConfigureAwait(
false
);
431
432
var frame =
new
byte
[header.Length + body.Length];
433
434
Buffer.BlockCopy(header, 0, frame, 0, header.Length);
435
Buffer.BlockCopy(body, 0, frame, header.Length, body.Length);
436
437
return
frame;
438
}
439
483
private
static
async Task
ReadExactlyAsync
(
484
NetworkStream stream,
485
byte
[] buffer,
486
CancellationToken cancellationToken)
487
{
488
var offset = 0;
489
490
while
(offset < buffer.Length)
491
{
492
var read = await stream.ReadAsync(
493
buffer.AsMemory(offset, buffer.Length - offset),
494
cancellationToken).ConfigureAwait(
false
);
495
496
if
(read == 0)
497
{
498
throw
new
IOException(
"The remote PLC closed the TCP connection."
);
499
}
500
501
offset += read;
502
}
503
}
504
520
private
Task
CloseCoreAsync
()
521
{
522
try
523
{
524
_stream
?.Close();
525
_stream
?.Dispose();
526
527
_tcpClient
?.Close();
528
_tcpClient
?.Dispose();
529
}
530
finally
531
{
532
_stream
=
null
;
533
_tcpClient
=
null
;
534
}
535
536
return
Task.CompletedTask;
537
}
538
554
private
void
ThrowIfDisposed
()
555
{
556
ObjectDisposedException.ThrowIf(
_disposed
, GetType().Name);
557
}
558
}
Dreamine.PLC.Mitsubishi.MC.Transport
Definition
FakeMitsubishiMcTransport.cs:3
Dreamine.PLC.Mitsubishi.MC.Transport.IMitsubishiMcTransport
Definition
IMitsubishiMcTransport.cs:14
Dreamine.PLC.Mitsubishi.MC.Transport.TcpMitsubishiMcTransport
Definition
TcpMitsubishiMcTransport.cs:15
Dreamine.PLC.Mitsubishi.MC.Transport.TcpMitsubishiMcTransport.SendAndReceiveAsync
async Task< PlcResult< byte[]> > SendAndReceiveAsync(IReadOnlyList< byte > requestFrame, int receiveTimeoutMs, int retryCount, CancellationToken cancellationToken=default)
Definition
TcpMitsubishiMcTransport.cs:285
Dreamine.PLC.Mitsubishi.MC.Transport.TcpMitsubishiMcTransport._stream
NetworkStream? _stream
Definition
TcpMitsubishiMcTransport.cs:42
Dreamine.PLC.Mitsubishi.MC.Transport.TcpMitsubishiMcTransport.DisconnectAsync
async Task< PlcResult > DisconnectAsync(CancellationToken cancellationToken=default)
Definition
TcpMitsubishiMcTransport.cs:209
Dreamine.PLC.Mitsubishi.MC.Transport.TcpMitsubishiMcTransport._disposed
bool _disposed
Definition
TcpMitsubishiMcTransport.cs:51
Dreamine.PLC.Mitsubishi.MC.Transport.TcpMitsubishiMcTransport._tcpClient
TcpClient? _tcpClient
Definition
TcpMitsubishiMcTransport.cs:33
Dreamine.PLC.Mitsubishi.MC.Transport.TcpMitsubishiMcTransport._syncLock
readonly SemaphoreSlim _syncLock
Definition
TcpMitsubishiMcTransport.cs:24
Dreamine.PLC.Mitsubishi.MC.Transport.TcpMitsubishiMcTransport.ReadExactlyAsync
static async Task ReadExactlyAsync(NetworkStream stream, byte[] buffer, CancellationToken cancellationToken)
Definition
TcpMitsubishiMcTransport.cs:483
Dreamine.PLC.Mitsubishi.MC.Transport.TcpMitsubishiMcTransport.IsConnected
bool IsConnected
Definition
TcpMitsubishiMcTransport.cs:61
Dreamine.PLC.Mitsubishi.MC.Transport.TcpMitsubishiMcTransport.ReceiveBinary3EFrameAsync
static async Task< byte[]> ReceiveBinary3EFrameAsync(NetworkStream stream, CancellationToken cancellationToken)
Definition
TcpMitsubishiMcTransport.cs:413
Dreamine.PLC.Mitsubishi.MC.Transport.TcpMitsubishiMcTransport.DisposeAsync
async ValueTask DisposeAsync()
Definition
TcpMitsubishiMcTransport.cs:355
Dreamine.PLC.Mitsubishi.MC.Transport.TcpMitsubishiMcTransport.ThrowIfDisposed
void ThrowIfDisposed()
Definition
TcpMitsubishiMcTransport.cs:554
Dreamine.PLC.Mitsubishi.MC.Transport.TcpMitsubishiMcTransport.CloseCoreAsync
Task CloseCoreAsync()
Definition
TcpMitsubishiMcTransport.cs:520
Dreamine.PLC.Mitsubishi.MC.Transport.TcpMitsubishiMcTransport.ConnectAsync
async Task< PlcResult > ConnectAsync(string host, int port, int timeoutMs, CancellationToken cancellationToken=default)
Definition
TcpMitsubishiMcTransport.cs:120
Transport
TcpMitsubishiMcTransport.cs
다음에 의해 생성됨 :
1.17.0