> `let private WaitForData (client : TcpClient, dataLength : int) : Async<bool>=` 

> `let mutable loopBreaker : bool = true`
> 
> `let isConnectionAlive : bool = IsConnectionEstablished client && client <> null`

You should only use explicit type declaration when the compiler demands it: 

`let private WaitForData (client : TcpClient) dataLength =` 

`let mutable loopBreaker = true`

`let isConnectionAlive = IsConnectionEstablished client && client <> null`


----------

> `let isConnectionAlive : bool = IsConnectionEstablished client && client <> null`

It seems rather risky to me that you use `client` in a function call before testing it for null. I would do it in reverse order:

    let isConnectionAlive = client <> null && IsConnectionEstablished client

But why evaluate the `client` for `null` in the loop in the first place? You should return false immediately if it's `null`.


----------

>                 Task.Delay(500) 
                |> Async.AwaitTask 
                |> ignore

I don't think this is actually waiting 500 ms as you may expect.

Instead you can do:

    do! Async.Sleep 500

or 

    do! Task.Delay(500) |> Async.AwaitTask 


----------
As Bohdan stupak shows you can do the same in a recursive fashion like:

    let private waitForData (client: TcpClient) dataLength = 
        let rec waiter () =
            async {
                if client = null then
                    return false
                    else 
                        match isConnected client, client.Available >= dataLength with
                        | true, true -> return true
                        | true, false ->
                            do! Async.Sleep 500
                            return! waiter ()
                        | false, dataFound -> return dataFound                            
            }
        waiter()