首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >用WaitForConnectionAsync()挂在管道上

用WaitForConnectionAsync()挂在管道上
EN

Stack Overflow用户
提问于 2015-09-10 21:14:43
回答 1查看 3.3K关注 0票数 3

我正在通过命名管道与另一个进程通信。管道服务器用C#实现,客户端用C语言编写,服务器是WPF应用程序。

我需要创建一个NamedPipeServerStream,并等待(同步)1秒才能连接到客户端。然后我需要知道客户是否有关联。

由于NamedPipeServerStream取消/超时客户端连接的唯一方法是通过它的异步WaitForConnectionAsync方法(这需要一个CancellationToken )来实现我认为是同步等待的方法,如下所示:

代码语言:javascript
运行
复制
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()函数在UI线程上运行。

应该使其同步的是访问它返回的异步WaitForConnectionAsyncSyncWrapper()函数的Result属性。为了访问结果,异步函数必须已经完全返回,并且它不能执行return pipe.IsConnected行,直到函数在await pipe.WaitForConnectionAsync(cts.Token);完成后才恢复。至少这是我的理解。

所以问题是:尽管客户端程序说它打开了我的服务器的管道(当然在上面的代码执行之前已经创建了),但是WaitOneSecondForClientConnect()永远不会返回。如果我闯入服务器,它就在这条线上:result = WaitForConnectionAsyncSyncWrapper().Result;

因此,我猜它是在等待任务的结果可用,如果客户机在1秒内连接,它应该是pipe.IsConnected的值;或者,如果由于令牌被取消(1秒后),当我访问AggregateException时,它应该抛出一个AggregateException。但它只是完全挂在地上。

另一方面,如果我在令牌启动前取消它(例如在调用Thread.Sleep(2000);之前放置一个await pipe.WaitForConnectionAsync(cts.Token); ),那么连接就会被成功取消(我认为它甚至不会尝试启动,因为令牌已经被取消了)--访问Result属性会抛出一个AggregateException等等.

有几件事要注意。

  • 如果我将WaitOneSecondForClientConnect()的内容替换为标准的同步pipe.WaitForConnection();,它每次都能工作-即客户端连接,函数返回。
  • 在我编写的测试程序中,最初是为了让异步/同步的东西工作,每次都以这种同步-异步的方式连接。这是一个控制台程序,而不是我真正的程序,即WPF。下面列出了测试程序的相关代码。
  • 上面发布的代码实际上已经运行了几次,失败了30到40次。
  • 如果我的客户端不打开我的管道,我的“真实”代码仍然挂起,而我的测试代码等待指定的时间段,然后打印“连接失败”。正如预期的那样(见下文)--这正是我真正的代码中应该发生的行为。

工作的测试代码:

代码语言:javascript
运行
复制
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.");
}

..。

代码语言:javascript
运行
复制
private static async Task<bool> ConnectAsync(NamedPipeServerStream pipe)
{
    CancellationTokenSource cts = new CancellationTokenSource(1000);
    await pipe.WaitForConnectionAsync(cts.Token);
    return pipe.IsConnected;
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-09-10 21:38:38

您不能像这样混合异步和非异步方法。正在发生的事情是,您的WaitOneSecondForClientConnect方法正在等待WaitForConnectionAsyncSyncWrapper方法的完成。但那家伙需要它的调用线程是自由的,这样它才能重新补充原来的上下文。所以你刚刚造成了一个僵局。有关详细信息,请参阅https://msdn.microsoft.com/en-us/magazine/jj991977.aspx

相反,您需要一直走下去。

代码语言:javascript
运行
复制
public async Task<bool> WaitOneSecondForClientConnect()
{
    bool result = false;
    try
    {
        result = await WaitForConnectionAsyncSyncWrapper();
    }
    catch (Exception e)
    {
        log.Write("Error waiting for pipe client connect: " + e.Message);
    }
    return result;
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32511714

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档