如何在F#中进行链式回调?

时间:2009-09-23 19:37:24

标签: f# asynchronous tcplistener

在C#中我使用的是TcpListener / TcpClient的异步版本,我通过回调方法链接这些版本,以便在回调完成时发布另一个Accept / Read。这是一个例子(未经测试):

    public void Start()
    {
        TcpListener listener = new TcpListener(IPAddress.Any, 3000);
        listener.Start();

        PostAccept(listener);
    }

    private void PostAccept(TcpListener listener)
    {
        listener.BeginAcceptTcpClient(AcceptCallback, listener);
    }

    private void AcceptCallback(IAsyncResult ar)
    {
        var listener = ar.AsyncState as TcpListener;

        if (listener == null)
        {
            return;
        }

        // get the TcpClient and begin a read chain in a similar manner

        PostAccept(listener);
    }

我的问题是我如何在F#中建模类似的东西?我会使用async关键字吗? BeginAcceptTcpClient,BeginRead等之后的代码本质上是将在回调函数中执行的代码吗?例如,这是正确的吗?

let accept(listener:TcpListener) = async {      
  let! client = listener.AsyncAcceptTcpClient()    
  // do something with the TcpClient such as beginning a Read chain
  accept(listener)
  return()
}    

上面的代码不起作用,因为未定义accept,并且在技术上标记它是不正确的,因为它不是一个递归方法?

2 个答案:

答案 0 :(得分:5)

@ kvb的回答是正确的,也是惯用的。

只是想指出你可以使用(喘气)循环:

let accept(t:TcpListener) =
    let completed = ref false 
    async {
        while not(!completed) do 
            let! client = t.AsyncAcceptTcpClient()
            if client <> null then
                Blah(client)
            else
                completed := true
    }

(这是在我的浏览器中输入代码,希望它可以编译)。这很好,因为你当然不能在C#代码中使用循环(必须使用开始/结束回调来跨越多个方法)。

答案 1 :(得分:4)

我不确定你的意思是“这不是一种反悔的方法”;如果你从它自己的定义中引用一个函数,那么它就是一个递归函数。我对Sockets类没有多少经验,但也许你正在寻找的是这些内容?

let rec accept(t : TcpListener) =
  async {
    let! client = t.AsyncAcceptTcpClient()

    // do some stuff with client here

    do! accept(t)
  }