Вчерновую накидал cross-process singleton на named pipes, плиз потыкайте носом
Ясен пень, что до юзабельного состояния пилить и пилить: вынести в отдельный класс, добавить разные имена для разных сессий, не забыть про обработку ошибок, запуск в фоновом потоке, прерывание работы и т.д. и т.п.
Меня сейчас интересуют в первую очередь упущенные нюансы/неверно указанные параметры/безопасность. Например, я почти уверен, что в коде дырка: не блокируются удалённые соединения. В понедельник буду на работе, проверю.
| код |
| using System;
using System.IO;
using System.IO.Pipes;
using System.Security.AccessControl;
using System.Security.Principal;
namespace ProcessSingleInstance
{
class Program
{
static void Main(string[] args)
{
string[] data = new[] { "a", "aaaaa", "qweqeqweqeqweqwert" };
NamedPipeServerStream server = null;
try
{
server = CreateServerStream();
}
catch (UnauthorizedAccessException)
{
}
if (server != null)
{
RunServer(server);
}
else
{
RunClient(data);
}
}
// критиковать здесь.
// Сервер должен _только_ читать данные;
// не должен позволять соединения вне текущей сессии, в т.ч. удалённые
private static NamedPipeServerStream CreateServerStream()
{
PipeSecurity security = new PipeSecurity();
security.AddAccessRule(
new PipeAccessRule(
WindowsIdentity.GetCurrent().User,
PipeAccessRights.Synchronize
| PipeAccessRights.ReadAttributes // DONTTOUCH: Required. I don't know why.
| PipeAccessRights.Write,
AccessControlType.Allow));
NamedPipeServerStream server = new NamedPipeServerStream(
"server",
PipeDirection.In, 1,
PipeTransmissionMode.Message, PipeOptions.WriteThrough, // Не уверен. Может, всё-таки использовать буфер?
4096, 4096,
security, HandleInheritability.None);
return server;
}
// и здесь
private static NamedPipeClientStream CreateClientStream()
{
NamedPipeClientStream client = new NamedPipeClientStream(
".", "server",
PipeDirection.Out, PipeOptions.WriteThrough, TokenImpersonationLevel.None, HandleInheritability.None);
return client;
}
private static void RunServer(NamedPipeServerStream server)
{
while (true)
{
Console.WriteLine("Wait...");
BinaryReader r = new BinaryReader(server);
server.WaitForConnection();
try
{
int count = r.ReadInt32();
for (int i = 0; i < count; i++)
{
Console.WriteLine(r.ReadString());
}
}
catch (IOException)
{ }
server.Disconnect();
}
}
private static void RunClient(string[] data)
{
using (NamedPipeClientStream client = CreateClientStream())
{
client.Connect();
using (BinaryWriter w = new BinaryWriter(client))
{
try
{
w.Write(data.Length);
foreach (var item in data)
{
w.Write(item);
}
client.WaitForPipeDrain();
}
catch (IOException)
{ }
}
}
}
}
}
|
| |