def __init__(self, name, addr, peers): self._name = name self._peers = peers self._comm = Communicator(name, addr) self._last_received = dict( ) # словарь для номеров последнего полученного сообщения от каждого отправителя self._seq_no = 0 # Sequence Number для последнего отправленного сообщения self._received = set() # множество всех полученных сообщений self._hold_back_queue = dict( ) # очередь сообщений для реализации порядка
class PingServer: def __init__(self, name, addr): self._comm = Communicator(name, addr) def run(self): while True: req = self._comm.recv() # process PING request if req.type == 'PING': resp = Message('PONG', req.body) self._comm.send(resp, req.sender) # unknown request else: err = Message('ERROR', 'unknown request type: %s' % req.type) self._comm.send(err, req.sender)
class RpcClient: """This is client-side RPC implementation""" def __init__(self, server_addr): self._comm = Communicator('client') self._server_addr = server_addr def call(self, func, *args): """Call function on RPC server and return result""" packet = list() packet.append(func) packet.extend(args) # Упаковываем всё в json и помещяем в body сообщения msg = Message('REQUEST', body=json.dumps(packet), sender=self._comm._addr) if func == 'append': # Для append'а никаких retry'ев, так как неидемпотентен self._comm.send(msg, self._server_addr) resp = self._comm.recv(1) if resp is None: raise Exception("Response timeout") elif resp.type == 'ERROR': raise Exception(resp.body) else: return resp.body else: while True: # для идемпотентных отправялем запросы пока не получим ответ self._comm.send(msg, self._server_addr) resp = self._comm.recv(timeout=1) if resp is None: continue elif resp.type == 'ERROR': raise Exception(resp.body) else: return resp.body
class Peer: def __init__(self, name, addr, peers): self._name = name self._peers = peers self._comm = Communicator(name, addr) def run(self): while True: msg = self._comm.recv() # local user wants to send a message to the chat if msg.type == 'SEND' and msg.is_local(): # basic broadcast bcast_msg = Message('BCAST', msg.body, {'from': self._name}) for peer in self._peers: self._comm.send(bcast_msg, peer) # received broadcasted message elif msg.type == 'BCAST': # deliver message to the local user deliver_msg = Message('DELIVER', msg.headers['from'] + ': ' + msg.body) self._comm.send_local(deliver_msg)
class PingClient: def __init__(self, name, server_addr): self._comm = Communicator(name) self._server_addr = server_addr def run(self): while True: command = self._comm.recv_local() # send PING to server if command.type == 'PING': self._comm.send(command, self._server_addr) resp = self._comm.recv(timeout=1) if resp is not None and resp.type == 'PONG': self._comm.send_local(resp) else: err = Message('ERROR', 'No reply from the server') self._comm.send_local(err) # unknown command else: err = Message('ERROR', 'unknown command: %s' % command.type) self._comm.send_local(err)
class Receiver: def __init__(self, name, addr): self._comm = Communicator(name, addr) def run(self): while True: msg = self._comm.recv() # deliver INFO-1 message to receiver user # underlying transport: unreliable with possible repetitions # goal: receiver knows all that were recieved but at most once if msg.type == 'INFO-1': pass # deliver INFO-2 message to receiver user # underlying transport: unreliable with possible repetitions # goal: receiver knows all at least once elif msg.type == 'INFO-2': pass # deliver INFO-3 message to receiver user # underlying transport: unreliable with possible repetitions # goal: receiver knows all exactly once elif msg.type == 'INFO-3': pass # deliver INFO-4 message to receiver user # underlying transport: unreliable with possible repetitions # goal: receiver knows all exactly once in the order elif msg.type == 'INFO-4': pass # unknown message else: err = Message('ERROR', 'unknown message type: %s' % msg.type) self._comm.send(err, msg.sender)
class Receiver: def __init__(self, name, addr): self._comm = Communicator(name, addr) self._received_msgs = set() # множество уже полученных сообщений def run(self): while True: msg = self._comm.recv() # deliver INFO-1 message to receiver user # underlying transport: unreliable with possible repetitions # goal: receiver knows all that were recieved but at most once if msg.type == 'INFO-1': if msg not in self._received_msgs: self._comm.send_local(msg) self._received_msgs.add(msg) # добавляем полученное сообщение # в множество уже полученных сообщений # чтобы не отправить одно сообщение дважды # deliver INFO-2 message to receiver user # underlying transport: unreliable with possible repetitions # goal: receiver knows all at least once elif msg.type == 'INFO-2': self._comm.send_local(msg) # а здесь можем отправлять сообщения сколь угодно self._comm.send(msg, msg._sender) # deliver INFO-3 message to receiver user # underlying transport: unreliable with possible repetitions # goal: receiver knows all exactly once elif msg.type == 'INFO-3': if msg not in self._received_msgs: self._comm.send_local(msg) self._received_msgs.add(msg) self._comm.send(msg, msg._sender) # здесь нам важно отправить ответ sender'у # deliver INFO-4 message to receiver user # underlying transport: unreliable with possible repetitions # goal: receiver knows all exactly once in the order elif msg.type == 'INFO-4': if msg not in self._received_msgs: self._comm.send_local(msg) self._received_msgs.add(msg) self._comm.send(msg, msg._sender) # здесь нам важно отправить ответ sender'у # unknown message else: err = Message('ERROR', 'unknown message type: %s' % msg.type) self._comm.send(err, msg.sender)
def __init__(self, name, addr): self._comm = Communicator(name, addr) self._received_msgs = set() # множество уже полученных сообщений
def __init__(self, name, server_addr): self._comm = Communicator(name) self._server_addr = server_addr
class Sender: def __init__(self, name, recv_addr): self._comm = Communicator(name) self._recv_addr = recv_addr self._local_messages = collections.deque( ) # очередь локальных сообщений def run(self): while True: try: # берём очередное локальное сообщение msg = self._local_messages.popleft() except IndexError: msg = self._comm.recv_local() # deliver INFO-1 message to receiver user # underlying transport: unreliable with possible repetitions # goal: receiver knows all that were recieved but at most once if msg.type == 'INFO-1': self._comm.send(msg, self._recv_addr) # просто отправляем # deliver INFO-2 message to receiver user # underlying transport: unreliable with possible repetitions # goal: receiver knows all at least once elif msg.type == 'INFO-2': while True: # отправляем и ждём ответ; self._comm.send( msg, self._recv_addr ) # если ответ - сообщение с локального сервера, resp = self._comm.recv( timeout=0.5 ) # то добавляем его в очередь и дальше ждём ответ if resp is None: # от receiver'а (с повторной отправкой) continue elif resp.is_local(): self._local_messages.append(resp) else: resp._sender = msg._sender if resp == msg: break # deliver INFO-3 message to receiver user # underlying transport: unreliable with possible repetitions # goal: receiver knows all exactly once elif msg.type == 'INFO-3': while True: # для INFO-3 логика такая же, как для INFO-2, self._comm.send( msg, self._recv_addr) # отличия есть только у receiver'a resp = self._comm.recv(timeout=0.5) if resp is None: continue elif resp.is_local(): self._local_messages.append(resp) else: resp._sender = msg._sender if resp == msg: break # deliver INFO-4 message to receiver user # underlying transport: unreliable with possible repetitions # goal: receiver knows all exactly once in the order elif msg.type == 'INFO-4': while True: # для INFO-4 логика такая же, как для INFO-2, self._comm.send( msg, self._recv_addr) # отличия есть только у receiver'a resp = self._comm.recv(timeout=0.5) if resp is None: continue elif resp.is_local( ): # порядок сохраняется потому, что новые self._local_messages.append( resp ) # локальные сообщения мы не отправляем до тех пор else: # пока не получим ответ от receiver'а resp._sender = msg._sender if resp == msg: break else: err = Message('ERROR', 'unknown command: %s' % msg.type) self._comm.send_local(err)
def __init__(self, name, recv_addr): self._comm = Communicator(name) self._recv_addr = recv_addr self._local_messages = collections.deque( ) # очередь локальных сообщений
def __init__(self, server_addr): self._comm = Communicator('client') self._server_addr = server_addr
def __init__(self, name, addr, peers): self._name = name self._peers = peers self._comm = Communicator(name, addr)
def __init__(self, name, recv_addr): self._comm = Communicator(name) self._recv_addr = recv_addr
def __init__(self, server_addr): self._comm = Communicator('client') # Your implementation pass
def __init__(self, name, addr): self._comm = Communicator(name, addr)
class Peer: def __init__(self, name, addr, peers): self._name = name self._peers = peers self._comm = Communicator(name, addr) self._last_received = dict( ) # словарь для номеров последнего полученного сообщения от каждого отправителя self._seq_no = 0 # Sequence Number для последнего отправленного сообщения self._received = set() # множество всех полученных сообщений self._hold_back_queue = dict( ) # очередь сообщений для реализации порядка def run(self): while True: msg = self._comm.recv() # local user wants to send a message to the chat if msg.type == 'SEND' and msg.is_local(): # basic broadcast self._seq_no += 1 bcast_msg = Message( 'BCAST', msg.body, { 'from': self._name, 'seq_no': self._seq_no, 'sender': self._name }) # будем добавлять имя процесса, # который отправил сообщение for peer in self._peers: self._comm.send(bcast_msg, peer) # received broadcasted message elif msg.type == 'BCAST': # deliver message to the local user # если сообщение уже обработали, то снова обрабатывать его не будем if (msg.body not in self._received) and (msg.headers['sender'] != self._name): self._received.add(msg.body) if msg.headers['from'] != self._name: msg.headers['sender'] = self._name for peer in self._peers: # после получения сообщения отправим его всем другим self._comm.send(msg, peer) # проверка порядка if msg.headers['seq_no'] == ( self._last_received.setdefault( msg.headers['from'], 0) + 1): deliver_msg = Message( 'DELIVER', msg.headers['from'] + ': ' + msg.body) self._comm.send_local(deliver_msg) self._last_received[msg.headers['from']] += 1 # чистим очередь while self._hold_back_queue.setdefault( msg.headers['from'], list()): if self._hold_back_queue[msg.headers['from']][0][0] == \ (self._last_received[msg.headers['from']] + 1): # отправляем сообщения из очереди последовательно (по порядку) next_msg = (heapq.heappop( self._hold_back_queue[msg.headers['from']]) )[1] deliver_msg = Message( 'DELIVER', next_msg.headers['from'] + ': ' + next_msg.body) self._comm.send_local(deliver_msg) self._last_received[msg.headers['from']] += 1 else: # если в очереди нет следующего сообщения, ничего не делаем break # если N-ое сообщение пришло быстрее, чем предыдущее, то не обрабатываем его, а добавляем в очередь elif msg.headers['seq_no'] > ( self._last_received.setdefault( msg.headers['from'], 0) + 1): heapq.heappush( self._hold_back_queue.setdefault( msg.headers['from'], list()), tuple((msg.headers['seq_no'], msg)))