Я создал службу Windows, которая является оболочкой для консольного приложения. Функционально он работает правильно, запуская и останавливая приложение с сохранением состояния. Единственная проблема, которую я заметил, заключается в том, что служба будет работать на 1 ядре на 100%. Кажется, он не вращает процессор при запуске его в режиме отладки VS2019, поэтому я не вижу причины, пытаясь отладить код. Это очень простая программа, которая использует Topshelf для создания сервиса windows. Я включил здесь два файла программы:
class Program
{
static void Main(string[] args)
{
var rc = HostFactory.Run(x =>
{
x.Service<BedrockServiceWrapper>(s =>
{
s.ConstructUsing(name => new BedrockServiceWrapper());
s.WhenStarted(tc => tc.Start());
s.WhenStopped(tc => tc.Stop());
});
x.RunAsNetworkService();
x.SetDescription("Windows Service Wrapper for Windows Bedrock Server");
x.SetDisplayName("BedrockService");
x.SetServiceName("BedrockService");
});
var exitCode = (int)Convert.ChangeType(rc, rc.GetTypeCode());
Environment.ExitCode = exitCode;
}
}
и
public class BedrockServiceWrapper
{
Process process;
Thread outputThread;
Thread errorThread;
Thread inputThread;
static BackgroundWorker bedrockServer;
string exePath;
public BedrockServiceWrapper()
{
exePath = ConfigurationManager.AppSettings["BedrockServerExeLocation"];
bedrockServer = new BackgroundWorker
{
WorkerSupportsCancellation = true
};
}
public void Stop()
{
process.StandardInput.WriteLine("stop");
bedrockServer.CancelAsync();
}
public void Start()
{
bedrockServer.DoWork += (s, e) =>
{
RunServer(exePath);
};
bedrockServer.RunWorkerAsync();
}
public void RunServer(string path)
{
// Fires up a new process to run inside this one
process = Process.Start(new ProcessStartInfo
{
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true,
WindowStyle = ProcessWindowStyle.Hidden,
FileName = path
});
// Depending on your application you may either prioritize the IO or the exact opposite
const ThreadPriority ioPriority = ThreadPriority.Highest;
outputThread = new Thread(outputReader) { Name = "ChildIO Output", Priority = ioPriority };
errorThread = new Thread(errorReader) { Name = "ChildIO Error", Priority = ioPriority };
inputThread = new Thread(inputReader) { Name = "ChildIO Input", Priority = ioPriority };
// Set as background threads (will automatically stop when application ends)
outputThread.IsBackground = errorThread.IsBackground
= inputThread.IsBackground = true;
// Start the IO threads
outputThread.Start(process);
errorThread.Start(process);
inputThread.Start(process);
process.WaitForExit();
}
/// <summary>
/// Continuously copies data from one stream to the other.
/// </summary>
/// <param name="instream">The input stream.</param>
/// <param name="outstream">The output stream.</param>
private static void passThrough(Stream instream, Stream outstream)
{
byte[] buffer = new byte[4096];
while (true)
{
int len;
while ((len = instream.Read(buffer, 0, buffer.Length)) > 0)
{
outstream.Write(buffer, 0, len);
outstream.Flush();
}
}
}
private static void outputReader(object p)
{
var process = (Process)p;
// Pass the standard output of the child to our standard output
passThrough(process.StandardOutput.BaseStream, Console.OpenStandardOutput());
}
private static void errorReader(object p)
{
var process = (Process)p;
// Pass the standard error of the child to our standard error
passThrough(process.StandardError.BaseStream, Console.OpenStandardError());
}
private static void inputReader(object p)
{
var process = (Process)p;
// Pass our standard input into the standard input of the child
passThrough(Console.OpenStandardInput(), process.StandardInput.BaseStream);
}
}
Может ли это быть что-то, связанное с потоками, копирующими входы и выходы между потоками? Я не верю, что о них много писали, но, возможно, это просто попытка скопировать множество фрагментов потока нулевой длины?
Github: https://github.com/ravetroll/BedrockService