Created
January 28, 2026 18:34
-
-
Save yaauie/37f5ed5abbc06dd73b5ce4bf1d55399c to your computer and use it in GitHub Desktop.
A listen-only TCP server with configurable read options for testing
This file contains hidden or 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
| #!/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