Простой Python — страница 64 из 66

Client read b'2014-06-03 01:29:01.463906'

Client read b'2014-06-03 01:29:06.465802'

Обе эти программы работают вечно, поэтому вам нужно завершать их вручную.

2. Используйте сокеты ZeroMQ REQ и REP, чтобы сделать то же самое.

Так выглядит файл zmq_time_server.py:

import zmq

from datetime import datetime

host = '127.0.0.1'

port = 6789

context = zmq.Context()

server = context.socket(zmq.REP)

server.bind("tcp://%s:%s" % (host, port))

print('Server started at', datetime.utcnow())

while True:

····#··Wait for next request from client

····message = server.recv()

····if message == b'time':

········now = datetime.utcnow()

········reply = str(now)

········server.send(bytes(reply, 'utf-8'))

········print('Server sent', reply)

А так — zmq_time_client.py:

import zmq

from datetime import datetime

from time import sleep

host = '127.0.0.1'

port = 6789

context = zmq.Context()

client = context.socket(zmq.REQ)

client.connect("tcp://%s:%s" % (host, port))

print('Client started at', datetime.utcnow())

while True:

····sleep(5)

····request = b'time'

····client.send(request)

····reply = client.recv()

····print("Client received %s" % reply)

Для простых сокетов вам нужно сначала запустить сервер. С помощью ZeroMQ вы можете запустить первым как клиент, так и сервер:

$ python zmq_time_server.py

Server started at 2014-06-03 01:39:36.933532

$ python zmq_time_client.py

Client started at 2014-06-03 01:39:42.538245

Через 15 секунд вы должны увидеть сообщения от сервера:

Server sent 2014-06-03 01:39:47.539878

Server sent 2014-06-03 01:39:52.540659

Server sent 2014-06-03 01:39:57.541403

Эти строки вы должны увидеть в сообщении от клиента:

Client received b'2014-06-03 01:39:47.539878'

Client received b'2014-06-03 01:39:52.540659'

Client received b'2014-06-03 01:39:57.541403'

3. Попробуйте сделать то же самое с помощью XMLRPC.

Сервер xmlrpc_time_server.py:

from xmlrpc.server import SimpleXMLRPCServer

def now():

····from datetime import datetime

····data = str(datetime.utcnow())

····print('Server sent', data)

····return data

server = SimpleXMLRPCServer(("localhost", 6789))

server.register_function(now, "now")

server.serve_forever()

И клиент xmlrpc_time_client.py:

import xmlrpc.client

from time import sleep

proxy = xmlrpc.client.ServerProxy("http://localhost:6789/")

while True:

····sleep(5)

····data = proxy.now()

····print('Client received', data)

Запустим сервер:

$ python xmlrpc_time_server.py

Запустим клиент:

$ python xmlrpc_time_client.py

Подождите примерно 15 секунд. Так выглядят первые три строки от сервера:

Server sent 2014-06-03 02:14:52.299122

127.0.0.1 — [02/Jun/2014 21:14:52] "POST / HTTP/1.1" 200 -

Server sent 2014-06-03 02:14:57.304741

127.0.0.1 — [02/Jun/2014 21:14:57] "POST / HTTP/1.1" 200 -

Server sent 2014-06-03 02:15:02.310377

127.0.0.1 — [02/Jun/2014 21:15:02] "POST / HTTP/1.1" 200 -

А так — первые три строки от клиента:

Client received 2014-06-03 02:14:52.299122

Client received 2014-06-03 02:14:57.304741

Client received 2014-06-03 02:15:02.310377

4. Возможно, вы видели эпизод телесериала I Love Lucy, в котором Люси и Этель работают на шоколадной фабрике (это классика). Парочка стала отставать, когда линия конвейера, которая направляла к ним на обработку конфеты, начала работать еще быстрее. Напишите симуляцию, которая отправляет разные типы конфет в список Redis, и клиент Lucy, который делает блокирующие выталкивания из списка. Ей нужно 0,5 секунды, чтобы обработать одну конфету. Выведите на экран время и тип каждой конфеты, которую получит Lucy, а также количество необработанных конфет:

redis_choc_supply.py передает бесконечное количество конфет:

import redis

import random

from time import sleep

conn = redis.Redis()

varieties = ['truffle', 'cherry', 'caramel', 'nougat']

conveyor = 'chocolates'

while True:

····seconds = random.random()

····sleep(seconds)

····piece = random.choice(varieties)

····conn.rpush(conveyor, piece)

redis_lucy.py может выглядеть так:

import redis

from datetime import datetime

from time import sleep

conn = redis.Redis()

timeout = 10

conveyor = 'chocolates'

while True:

····sleep(0.5)

····msg = conn.blpop(conveyor, timeout)

····remaining = conn.llen(conveyor)

····if msg:

········piece = msg[1]

········print('Lucy got a', piece, 'at', datetime.utcnow(),

········', only', remaining, 'left')

Запустите их в любом порядке. Поскольку Люси требуется полсекунды для обработки каждой конфеты и они появляются в среднем каждые полсекунды, это становится похоже на гонку. Чем раньше вы запустите конвейер, тем более сложной сделаете жизнь Люси:

$ python redis_choc_supply.py&

$ python redis_lucy.py

Lucy got a b'nougat' at 2014-06-03 03:15:08.721169, only 4 left

Lucy got a b'cherry' at 2014-06-03 03:15:09.222816, only 3 left

Lucy got a b'truffle' at 2014-06-03 03:15:09.723691, only 5 left

Lucy got a b'truffle' at 2014-06-03 03:15:10.225008, only 4 left

Lucy got a b'cherry' at 2014-06-03 03:15:10.727107, only 4 left

Lucy got a b'cherry' at 2014-06-03 03:15:11.228226, only 5 left

Lucy got a b'cherry' at 2014-06-03 03:15:11.729735, only 4 left

Lucy got a b'truffle' at 2014-06-03 03:15:12.230894, only 6 left

Lucy got a b'caramel' at 2014-06-03 03:15:12.732777, only 7 left

Lucy got a b'cherry' at 2014-06-03 03:15:13.234785, only 6 left

Lucy got a b'cherry' at 2014-06-03 03:15:13.736103, only 7 left

Lucy got a b'caramel' at 2014-06-03 03:15:14.238152, only 9 left

Lucy got a b'cherry' at 2014-06-03 03:15:14.739561, only 8 left

Бедная Люси.

5. Используйте ZeroMQ, чтобы публиковать стихотворение из упражнения 7 главы 7 по одному слову за раз. Напишите потребителя ZeroMQ, который будет выводить на экран каждое слово, начинающееся с гласной. Напишите другого потребителя, который будет выводить все слова, состоящие из пяти букв. Знаки препинания игнорируйте.