Загрузка данных
manager
using System;
using System.Diagnostics;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.IO.Pipes;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
const string MemoryName = "PipeWorkerState";
const string MutexName = "PipeWorkerStateMutex";
string path = @"C:\Users\mompr\source\repos\PipeWorker\bin\Debug\net8.0\PipeWorker.exe";
if (!File.Exists(path))
{
Console.WriteLine("Worker executable not found.");
return;
}
using var memory = MemoryMappedFile.CreateOrOpen(MemoryName, 1024);
using var view = memory.CreateViewAccessor();
using var mutex = new Mutex(false, MutexName);
mutex.WaitOne();
try
{
view.Write(0, 0);
view.Write(4, false);
view.Write(8, 0);
WriteString(view, 12, "", 128);
WriteString(view, 140, "", 256);
}
finally
{
mutex.ReleaseMutex();
}
using var requestPipe = new AnonymousPipeServerStream(
PipeDirection.Out, HandleInheritability.Inheritable);
using var responsePipe = new AnonymousPipeServerStream(
PipeDirection.In, HandleInheritability.Inheritable);
var startInfo = new ProcessStartInfo(path)
{
UseShellExecute = true,
CreateNoWindow = false
};
startInfo.ArgumentList.Add(requestPipe.GetClientHandleAsString());
startInfo.ArgumentList.Add(responsePipe.GetClientHandleAsString());
using Process process = Process.Start(startInfo)!;
requestPipe.DisposeLocalCopyOfClientHandle();
responsePipe.DisposeLocalCopyOfClientHandle();
Console.WriteLine("Worker started.");
Console.WriteLine("Commands: stop, exit");
SendMessage(requestPipe, "TASK|Start|15");
Task<string?> inputTask = Task.Run(Console.ReadLine);
while (true)
{
if (process.HasExited)
{
Console.WriteLine("Worker unavailable.");
break;
}
if (inputTask.IsCompleted)
{
string command = (inputTask.Result ?? "").Trim();
if (command.Equals("stop", StringComparison.OrdinalIgnoreCase))
{
Console.WriteLine("Stopping Worker...");
if (!process.HasExited)
process.Kill();
process.WaitForExit();
Console.WriteLine("Worker unavailable.");
break;
}
if (command.Equals("exit", StringComparison.OrdinalIgnoreCase))
{
if (!process.HasExited)
process.Kill();
process.WaitForExit();
break;
}
Console.WriteLine("Unknown command. Use stop or exit.");
inputTask = Task.Run(Console.ReadLine);
}
WorkerState state = ReadState(view, mutex);
Console.WriteLine(
$"Task: {state.TaskId}, Progress: {state.Progress}%, " +
$"Running: {state.IsRunning}, Status: {state.Status}, " +
$"CurrentTask: {state.CurrentTask}");
if (state.Progress == 100 && !state.IsRunning)
break;
Thread.Sleep(300);
}
if (!process.HasExited)
{
try
{
string response = ReadMessage(responsePipe);
Console.WriteLine($"Response: {response}");
}
catch (IOException)
{
Console.WriteLine("Worker unavailable.");
}
}
static WorkerState ReadState(
MemoryMappedViewAccessor view, Mutex mutex)
{
mutex.WaitOne();
try
{
return new WorkerState(
view.ReadInt32(0),
view.ReadBoolean(4),
view.ReadInt32(8),
ReadString(view, 12, 128),
ReadString(view, 140, 256));
}
finally
{
mutex.ReleaseMutex();
}
}
static void SendMessage(Stream pipe, string message)
{
byte[] data = Encoding.UTF8.GetBytes(message);
byte[] length = BitConverter.GetBytes(data.Length);
pipe.Write(length, 0, length.Length);
pipe.Write(data, 0, data.Length);
pipe.Flush();
}
static string ReadMessage(Stream pipe)
{
byte[] length = new byte[4];
pipe.ReadExactly(length, 0, 4);
int size = BitConverter.ToInt32(length, 0);
if (size < 0 || size > 1024 * 1024)
throw new InvalidDataException("Invalid message length.");
byte[] data = new byte[size];
pipe.ReadExactly(data, 0, size);
return Encoding.UTF8.GetString(data);
}
static void WriteString(
MemoryMappedViewAccessor view, int offset,
string text, int maxBytes)
{
byte[] data = Encoding.UTF8.GetBytes(text);
int len = Math.Min(data.Length, maxBytes - 4);
view.Write(offset, len);
view.WriteArray(offset + 4, data, 0, len);
}
static string ReadString(
MemoryMappedViewAccessor view, int offset, int maxBytes)
{
int len = view.ReadInt32(offset);
if (len < 0 || len > maxBytes - 4)
return "";
byte[] data = new byte[len];
view.ReadArray(offset + 4, data, 0, len);
return Encoding.UTF8.GetString(data);
}
class WorkerState
{
public int Progress { get; }
public bool IsRunning { get; }
public int TaskId { get; }
public string Status { get; }
public string CurrentTask { get; }
public WorkerState(int progress, bool isRunning, int taskId,
string status, string currentTask)
{
Progress = progress;
IsRunning = isRunning;
TaskId = taskId;
Status = status;
CurrentTask = currentTask;
}
}
worker
using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.IO.Pipes;
using System.Text;
using System.Threading;
const string MemoryName = "PipeWorkerState";
const string MutexName = "PipeWorkerStateMutex";
if (args.Length < 2)
return;
using var inputPipe = new AnonymousPipeClientStream(
PipeDirection.In, args[0]);
using var outputPipe = new AnonymousPipeClientStream(
PipeDirection.Out, args[1]);
using var memory = MemoryMappedFile.CreateOrOpen(MemoryName, 1024);
using var view = memory.CreateViewAccessor();
using var mutex = new Mutex(false, MutexName);
string message = ReadMessage(inputPipe);
if (!TryParseMessage(message, out string type,
out string command, out string payload))
{
SendMessage(outputPipe, "RESULT|Error: bad message format");
return;
}
if (type != "TASK" || command != "Start")
{
SendMessage(outputPipe, "RESULT|Error: unknown command");
return;
}
int taskId = int.TryParse(payload, out int id) ? id : 15;
Console.WriteLine($"Task started: {taskId}");
for (int progress = 0; progress <= 100; progress += 10)
{
UpdateState(view, mutex, progress, true, taskId,
progress == 0 ? "Starting" : "Processing",
"Processing data.csv");
Thread.Sleep(500);
}
UpdateState(view, mutex, 100, false, taskId,
"Finished", "None");
SendMessage(outputPipe, $"RESULT|Done task {payload}");
static bool TryParseMessage(string raw, out string type,
out string command, out string payload)
{
type = command = payload = "";
string[] parts = raw.Split('|', 3);
if (parts.Length != 3)
return false;
type = parts[0];
command = parts[1];
payload = parts[2];
return true;
}
static void UpdateState(MemoryMappedViewAccessor view,
Mutex mutex, int progress, bool running, int taskId,
string status, string currentTask)
{
mutex.WaitOne();
try
{
view.Write(0, progress);
view.Write(4, running);
view.Write(8, taskId);
WriteString(view, 12, status, 128);
WriteString(view, 140, currentTask, 256);
}
finally
{
mutex.ReleaseMutex();
}
}
static void SendMessage(Stream pipe, string message)
{
byte[] data = Encoding.UTF8.GetBytes(message);
byte[] length = BitConverter.GetBytes(data.Length);
pipe.Write(length, 0, length.Length);
pipe.Write(data, 0, data.Length);
pipe.Flush();
}
static string ReadMessage(Stream pipe)
{
byte[] length = new byte[4];
pipe.ReadExactly(length, 0, 4);
int size = BitConverter.ToInt32(length, 0);
if (size < 0 || size > 1024 * 1024)
throw new InvalidDataException("Invalid message length.");
byte[] data = new byte[size];
pipe.ReadExactly(data, 0, size);
return Encoding.UTF8.GetString(data);
}
static void WriteString(MemoryMappedViewAccessor view,
int offset, string text, int maxBytes)
{
byte[] data = Encoding.UTF8.GetBytes(text);
int len = Math.Min(data.Length, maxBytes - 4);
view.Write(offset, len);
view.WriteArray(offset + 4, data, 0, len);
}