Last active
March 13, 2024 14:32
-
-
Save lucasteles/5bdd2e87eb4b85a10ba2ebc73ec08eef to your computer and use it in GitHub Desktop.
F# UDP Socket
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
open System.Net.Sockets | |
open System.Net | |
open System | |
open System.Text | |
open System.Threading | |
let localPort = 8800 | |
let serverPort = 8888 | |
let serverUri = Uri("http://localhost") | |
let log msg = printfn $"{DateTime.Now}: %A{msg}" | |
let socket = | |
new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp) | |
socket.Blocking <- false | |
socket.Bind(new IPEndPoint(IPAddress.Any, localPort)) | |
let cts = new CancellationTokenSource() | |
let ct = cts.Token | |
let bufferSize = 1024 | |
let stop () = | |
use _ = cts | |
use _ = socket | |
cts.CancelAsync() |> Async.AwaitTask |> Async.RunSynchronously | |
let receiver = | |
task { | |
let buffer = GC.AllocateArray<byte>(bufferSize, pinned = true) | |
let anyEndPoint = new IPEndPoint(IPAddress.Any, 0) | |
log "start receiveing..." | |
while not ct.IsCancellationRequested do | |
try | |
let! recv = socket.ReceiveFromAsync(buffer, anyEndPoint, ct) | |
log $"recv {Encoding.UTF8.GetString(buffer)} from {recv.RemoteEndPoint}" | |
with :? OperationCanceledException -> | |
log "stopping receiver..." | |
log "receiver stopped!" | |
} | |
let sender = | |
MailboxProcessor.Start( | |
(fun (inbox) -> | |
async { | |
let buffer = GC.AllocateArray<byte>(bufferSize, pinned = true) | |
let serverAddresses = | |
Dns.GetHostAddresses(serverUri.DnsSafeHost, AddressFamily.InterNetwork) | |
let serverEndpoint = IPEndPoint(serverAddresses[0], serverPort) | |
log "start sending..." | |
while not ct.IsCancellationRequested do | |
let! (msg: IUtf8SpanFormattable) = inbox.Receive() | |
let mutable size = 0 | |
let ok = msg.TryFormat(buffer, &size, ReadOnlySpan.Empty, null) | |
if not ok || size = 0 then | |
log $"unnable to format %A{msg}" | |
let bufferSlice = buffer.AsMemory().Slice(0, size) | |
try | |
let! bytesSend = socket.SendToAsync(bufferSlice, serverEndpoint, ct).AsTask() |> Async.AwaitTask | |
log $"sent {bytesSend} bytes to {serverEndpoint}" | |
with :? OperationCanceledException -> | |
log "stopping sender..." | |
log "sender stopped!" | |
}), | |
ct | |
) | |
sender.Post (Guid.NewGuid()) | |
stop() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment