Я общаюсь с другим процессом через именованные каналы. Сервер трубопроводов реализован на C#, а клиент написан на C. Сервер - это приложение WPF.Висячие с WaitForConnectionAsync() на трубе
Мне нужно создать NamedPipeServerStream
и подождать (синхронно) до 1 секунды для подключения клиента. И тогда мне нужно знать, подключен ли клиент.
Как единственный способ NamedPipeServerStream
«s, чтобы отменить/таймаут ожидания для клиента подключения осуществляется через его асинхронный WaitForConnectionAsync
метод - которая принимает CancellationToken
- Я реализовал то, что я считаю, является синхронным ждать так:
public bool WaitOneSecondForClientConnect()
{
bool result = false;
try
{
result = WaitForConnectionAsyncSyncWrapper().Result;
}
catch (AggregateException e)
{
log.Write("Error waiting for pipe client connect: " + e.InnerException.Message);
}
return result;
}
private async Task<bool> WaitForConnectionAsyncSyncWrapper()
{
CancellationTokenSource cts = new CancellationTokenSource(1000);
await pipe.WaitForConnectionAsync(cts.Token);
return pipe.IsConnected;
}
Труба определяется следующим образом: NamedPipeServerStream(pipeName, PipeDirection.Out, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous, 1, 1);
Функция WaitOneSecondForClientConnect()
работает на потоке пользовательского интерфейса.
Что должно сделать синхронным доступ к функции WaitForConnectionAsyncSyncWrapper()
функции async Result
на Task<bool>
, она возвращается. Чтобы получить доступ к результату, функция async должна быть полностью возвращена, и она не может выполнить строку return pipe.IsConnected
до тех пор, пока функция не будет возобновлена после завершения await pipe.WaitForConnectionAsync(cts.Token);
. По крайней мере, это мое понимание.
Итак, проблема: хотя клиентская программа говорит, что она открыла трубку моего сервера (которая уже была создана, конечно, до того, как код выше выполнит), WaitOneSecondForClientConnect()
никогда не возвращается. Если я прорвусь на сервер, он находится в этой строке: result = WaitForConnectionAsyncSyncWrapper().Result;
.
Так что я предполагаю, что он ждет результат Целевой быть доступным, которое должно быть значение pipe.IsConnected
, если клиент подключен в течение 1 секунды, или он должен бросить AggregateException
, когда я к нему доступ, если await
завершена, поскольку маркер был отменен (через 1 секунду). Но он просто висит полностью.
С другой стороны, если я отменяю токен перед его началом, например. поставив Thread.Sleep(2000);
прямо перед вызовом await pipe.WaitForConnectionAsync(cts.Token);
, то соединение успешно отменен (я думаю, что это даже не пытается начать, потому что маркер уже отменен) - доступ к Result
собственности бросает AggregateException
и т.д ...
Несколько замечаний.
- Если я заменяю содержание
WaitOneSecondForClientConnect()
с стандартного синхронногоpipe.WaitForConnection();
, он работает каждый раз - т.е. клиент соединяется, и функция возвращает. - В тестовой программе, которую я написал, чтобы сначала получить эту работу с асинхронным/синхронизирующим файлом, соединение в этом синхронно-асинхронном режиме работает каждый раз. Это консольная программа, в отличие от моей реальной программы, которая представляет собой WPF. Соответствующий код тестовой программы приведен ниже.
- Код, указанный выше, фактически работал пару раз и не мог быть 30-40 раз.
- Если мой клиент не открывает мою трубу, мой «настоящий» код все еще зависает, тогда как мой тестовый код ждет указанный период времени, а затем печатает сообщение «Connection failed». как и ожидалось (см. ниже) - это именно то поведение, которое должно происходить в моем реальном коде.
тест код, который работает:
var pipe = new NamedPipeServerStream("SemiUsefulPipe_" + pid.ToString() + "ctest", PipeDirection.Out, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous, 1, 1);
// ... dll containing pipe client is injected in client process at this point.
try
{
var result = ConnectAsync(pipe).Result;
}
catch (AggregateException)
{
Console.WriteLine("Connection failed.");
}
...
private static async Task<bool> ConnectAsync(NamedPipeServerStream pipe)
{
CancellationTokenSource cts = new CancellationTokenSource(1000);
await pipe.WaitForConnectionAsync(cts.Token);
return pipe.IsConnected;
}
Вы не используете функцию async/wait правильно –
Возможно, нет - не могли бы вы разработать? – eurotrash
Ваш вопрос слишком длинный для меня, чтобы все это принять и сформулировать ответ –