Skip to content

Instantly share code, notes, and snippets.

@yaauie
Created January 28, 2026 18:34
Show Gist options
  • Select an option

  • Save yaauie/37f5ed5abbc06dd73b5ce4bf1d55399c to your computer and use it in GitHub Desktop.

Select an option

Save yaauie/37f5ed5abbc06dd73b5ce4bf1d55399c to your computer and use it in GitHub Desktop.
A listen-only TCP server with configurable read options for testing
#!/usr/bin/env ruby
require 'socket'
require 'optparse'
require 'thread'
config = {
port: 0,
lag_ms: 0,
jitter_ms: 0,
buffer_bytes: 1024
}
OptionParser.new do |opts|
opts.banner = "Usage: mock-tcpserver [options]"
opts.on("-pPORT", '--port=PORT', 'specify port') do |port|
config[:port] = Integer(port)
end
opts.on("-lLAGMS", "--lag=LAGMS", 'specify lag in millis') do |lag_ms|
config[:lag_ms] = Integer(lag_ms)
end
opts.on("-jJITTERMS", "--jitter", 'specify max jitter in millis') do |jitter_ms|
config[:jitter_ms] = Integer(jitter_ms)
end
opts.on("-bBUFFSIZE", '--buffer-size=BUFFERSIZE', 'specify buffer size in bytes') do |buffer_bytes|
config[:buffer_bytes] = Integer(buffer_bytes)
end
end.parse!
global_mutex = Mutex.new
fmt_addr = -> (addr) { addr.include?(?:) ? "[#{addr}]" : addr }
sync_puts = -> (io, message) { global_mutex.synchronize { io.puts(message) } }
buffer_bytes = config[:buffer_bytes]
effective_lag_ms = case
when config[:lag_ms] <= 0 then ->() { 0 }
when config[:jitter_ms] <= 0 then ->() { config[:lag_ms] }
else ->() { config[:lag_ms] + Random.rand(config[:jitter_ms])}
end
server = TCPServer.new(config.fetch(:port, 0))
self_afam, self_port, self_hostname, self_addr = server.addr
sync_puts[$stderr, "LISTEN[#{self_afam}->#{fmt_addr[self_hostname]}:#{self_port}]"]
loop do
Thread.start(server.accept) do |client|
peer_afam, peer_port, peer_hostname, peer_addr = client.peeraddr
client_desc = "#{peer_afam}<-#{fmt_addr[peer_hostname]}:#{peer_port}"
sync_puts[$stderr, "OPEN[#{client_desc}]"]
begin
loop do
buf = client.readpartial(buffer_bytes)
sync_puts[$stderr, "BUFF[#{client_desc}]<-(#{buf.length})"]
lag_ms = effective_lag_ms[]
sleep(Rational(lag_ms, 1000)) if (lag_ms > 0)
end
rescue EOFError
sync_puts[$stderr, "EOF[#{client_desc}]"]
client.close
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment