Search code examples
f#tcpclienttcplistener

F# TcpListener/Client class do not write?


I'm trying to setup server/client, at the moment I'm just doing an echo server to make sure that the connection to the listener and the client works.

but i got a problem, when trying to send data to my server from a simple client It don't get send or it get send after I force shutdown the client in the terminal.

I have written a server/client app before in C, but I'm trying in F# right now.

Client code:

let Client (ip :IPAddress, port) =
   use client = new TcpClient(ip.ToString(), port)
   use reader = new StreamReader (client.GetStream())
   use writer = new StreamWriter (client.GetStream())
   writer.AutoFlush <- true
   let mutable run = true


   while run do
       let input = Console.ReadLine()
       if input = "Exit"
       then run <- false
       else
           writer.Write input
           reader.ReadToEnd()
           |> printfn "got : %s"

Server code:

  let Server (ip : IPAddress, port) =
       let connlst = TcpListener(ip, port)

       connlst.Start() 

       let mutable run = true

       while run do
           use client = connlst.AcceptTcpClient()
           async {
                   use reader = new StreamReader (client.GetStream())
                   use writer = new StreamWriter (client.GetStream())
                   writer.AutoFlush <- true
                
                   printfn "Got : %s" (reader.ReadToEnd())
                   writer.WriteLine "hello"
           }
           |> Async.Start

           if Console.ReadLine() = "Exit" 
           then run <- false
           else ()

This is functions run inside the main function of both applications. If I startup the server in the terminal and enter the ip:port into my browser it connects fine give me the http request and all. but the sending back part does not send. (writer.write)

If I'm connecting my client it will connect but not send the message until I force the client to shut down, I have tried not to wrap the stream into a StreamWriter that did not help.


Solution

  • I see in the comments that you found the main issue (missing end-of-file character). However, I think there is one potential issue in the server code that is worth addressing (even though it's not causing any troubles right now).

    The potential issue is that you bind the client value using use, but then use it in an async block that is started in the background.

    while true do 
      use client = connlst.AcceptTcpClient()
      async {
        // #1 use 'client' here
      } |> Async.Start
      // #2 do some more work here
    

    If the iteration of the loop (#2) completed before the async block (#1) completes, then it would dispose of the client while it may still be in use in the async block. A simple trick to avoid this issue would be to use use inside async:

    while true do 
      let client = connlst.AcceptTcpClient()
      async {
        use client = client
        // #1 use 'client' here
      } |> Async.Start
      // #2 do some more work here