print line[(v-1)*DIE_WIDTH, DIE_WIDTH]
print ' '
end
puts
end
end
draw_dice(get_random_numbers(5, 1, 6))
Здесь мы воспользовались классом Net::НТТР
для прямого взаимодействия с Web- сервером. Считайте, что эта программа — узкоспециализированный браузер. Мы формируем URL и пытаемся установить соединение; когда оно будет установлено, мы получаем ответ, возможно, содержащий некие данные. Если код ответа показывает, что ошибок не было, то можно разобрать полученные данные. Предполагается, что исключения будут обработаны вызывающей программой.
Посмотрим на вариацию этой идеи. Что если вы захотели бы применить случайные числа в каком- нибудь приложении? Поскольку обслуживающая программа на стороне сервера позволяет указать количество возвращаемых чисел, то было бы логично сохранить их в буфере. Учитывая, что при обращении к удаленному серверу задержки неизбежны, следует сразу заполнить буфер во избежание лишних запросов по сети.
В листинге 18.5 эта мысль реализована. Буфер заполняется отдельным потоком и совместно используется всеми экземплярами класса. Размер буфера и «нижняя отметка» (@slack
) настраиваются; какие значения задать в реальной программе, зависит от величины задержки при обращении к серверу и от того, как часто приложение выбирает случайное число из буфера.
require 'net/http'
require 'thread'
class TrueRandom
def initialize(min=nil,max=nil,buff=nil,slack=nil)
@buffer = []
@site = 'www.random.org'
if ! defined? @init_flag
# Принять умолчания, если они не были заданы явно И
# это первый созданный экземпляр класса...
@min = min || 0
@max = max || 1
@bufsize = buff || 1000
@slacksize = slack || 300
@mutex = Mutex.new
@thread = Thread.new { fillbuffer }
@init_flag = TRUE # Значение может быть любым.
else
@min = min || @min
@max = max || @max
@bufsize = buff || @bufsize
@slacksize = slack || @slacksize
end
@url = '/cgi-bin/randnum' +
'?num=#@bufsize&min=#@min&max=#@max&col=1'
end
def fillbuffer
h = Net::HTTP.new(@site, 80)
resp, data = h.get(@url, nil)
@buffer += data.split
end
def rand
num = nil
@mutex.synchronize { num = @buffer.shift }
if @buffer.size < @slacksize
if ! @thread.alive?
@thread = Thread.new { fillbuffer }
end
end
if num == nil
if @thread.alive?
@thread.join
else
@thread = Thread.new { fillbuffer }
@thread.join
end
@mutex.synchronize { num = @buffer.shift }
end
num.to_i
end
end
t = TrueRandom.new(1,6,1000,300)
count = {1=>0, 2=>0, 3=>0, 4=>0, 5=>0, 6=>0}
10000.times do |n|
x = t.rand
count[x] += 1
end
p count
# При одном прогоне:
# {4=>1692, 5=>1677, 1=>1678, 6=>1635, 2=>1626, 3=>1692}
18.2.2. Запрос к официальному серверу времени
Как мы и обещали, приведем программу для обращения к NTP-серверу в сети (NTP — Network Time Protocol (синхронизирующий сетевой протокол). Показанный ниже код заимствован с небольшой