Skip to content
vtortola edited this page Nov 25, 2014 · 2 revisions

This is an implementation of the Echo Server example in F# as a demonstration of how to use WebSocketListener in this language.

The source code can be found HERE

Helpers

First, I created some helpers to simplify the work with the library.

A extension method to accept websockets asynchronusly using Async<WebSocket> rather than Task<WebSocket:

type WebSocketListener with
  member x.AsyncAcceptWebSocket = async {
    let! client = Async.AwaitTask <| x.AcceptWebSocketAsync cancellation.Token
    if(not(isNull client)) then
        return Some client
    else 
        return None
  }

Also, two extension methods on the WebSocket class to receive/send string messages:

type WebSocket with
  member x.AsyncReadString = async {
    let! message = Async.AwaitTask <| x.ReadMessageAsync cancellation.Token
    if(not(isNull message)) then
        use reader = new StreamReader(message)
        return Some (reader.ReadToEnd())
    else
        return None
  }
  member x.AsyncSendString (input:string) = async {
    use writer = new StreamWriter(x.CreateMessageWriter(WebSocketMessageType.Text), Encoding.UTF8)
    writer.Write input
    do! writer.FlushAsync() |> Async.AwaitIAsyncResult |> Async.Ignore
  }

Setting up the service

[<EntryPoint>]
let main argv =
    let options = 
        let opt = new WebSocketListenerOptions()
        opt.PingTimeout <- TimeSpan.FromSeconds(20.)
        opt.SubProtocols <- [|"text"|]
        opt
 
    let endpoint = new IPEndPoint(IPAddress.Any,9005)
    use listener = new WebSocketListener(endpoint, options)
    listener.Standards.RegisterStandard(new Rfc6455.WebSocketFactoryRfc6455(listener))
 
    Async.Start <| AsyncAcceptClients listener
    listener.Start()
    Log [|"Echo Server started at "; endpoint.ToString()|];
   
    Console.ReadKey true |> ignore
    listener.Stop()
    cancellation.Cancel()
    Log "Server stopped";
    Console.ReadKey true |> ignore
    0 // return an integer exit code

Accepting connections

let AsyncAcceptClients(listener : WebSocketListener) =
  async {
    while not cancellation.IsCancellationRequested && listener.IsStarted do
        let! result = Async.Catch listener.AsyncAcceptWebSocket
        match result with
        | Choice1Of2 result -> 
            match result with
                | None -> ignore()
                | Some client -> Async.Start <| AsyncAcceptMessages client
        | Choice2Of2 error -> 
            Log [|"Error Accepting clients: "; error.Message|]
    Log "Server Stop accepting clients"
  }

Receiving and echoing messages

let AsyncAcceptMessages(client : WebSocket) =
  async {
    while client.IsConnected do
        let! result = Async.Catch client.AsyncReadString 
        match result with
        | Choice1Of2 result -> 
            match result with
            | None -> ignore()
            | Some content -> do! client.AsyncSendString content
        | Choice2Of2 error -> 
            Log [|"Error Handling connection: "; error.Message|]
    Log [|"WebSocket "; (client.RemoteEndpoint.ToString()); " disconnected"|]
  }