TCPServer

Как и большинство языков программирования Ruby предоставляет в стандартной поставке набор методов и классов для работы с сокетами. Здесь мы рассмотрим создание простейшего tcp сервера. И не простейшего, использующего пул подключений. Если нужна производительность, но лень думать - всегда есть EventMachine, а если хочется ещё большей абстракции от обработки HTTP - можно взять всякие thin.

Простейший пример

Состоит из открытия сокета и ожидания подключения пользователей, отправки им сообщения и разрыва соединения

require 'socket'
 
server = TCPServer.new('127.0.0.1','8800')
 
loop do
  client = server.accept
 
  data = client.gets
  puts data
 
  client.puts('Hello client')
  client.close
end

Код простой и незамысловатый. Поддерживает одно временно одно подключение. Для проверки работы можно использовать netcat

nc 127.0.0.1 8800

Ввести любое сообщение и нажать Enter.

Обработка нескольких подключений

Или так называемый пул соединений. Данная возможно позволит, например, в будущем реализовать чат или что-нибудь с несколькими клиентами. А пока я оставлю здесь только заготовку. За потоки можно почитать рядом

require 'socket'
require 'thread'
require 'json'
 
def accept(client)
  puts "Client connected"
  begin
    data = client.gets
    raise "Connection closed" unless data
 
    data = JSON.parse(data.chomp!)
 
    client.puts(JSON.generate({return: 'ok'}))
  rescue RuntimeError => e
    puts e
  rescue => e
    client.puts "{error:\"#{e.class}\"}"
  end
  client.close
 
  puts "Client disconnected"
end
 
server = TCPServer.new('127.0.0.1','8800')
 
threads = []
 
loop {
  client = server.accept
 
  threads.delete_if do |t|
    unless t.alive?
      t.join
      true
    end
  end
 
  if threads.length >= 4
    client.puts '{error:"Too many connections. Try again later."}'
    client.close
    next
  end
 
  th = Thread.new do
    accept(client)
  end
 
  threads << th
}

Вкратце - в примере выше мы создали массив, который по сути служит для отслеживания количества активных в данный момент подключений. При превышении этого количества пользователю выдаётся ошибка и соединение разрывается. Так же используется магия, которая для Ruby, например, не очень хорошо описана, как то - если поток завершил своё выполнение - надо не забывать к нему подключаться, чтобы освобождать занятые им ресурсы1)

1)
с другой стороны коллега недавно рассказал мне о non-joinable потоках, но почитать за них я ещё не успел, увы