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.
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