opensistemas-hub / osbrain

osBrain - A general-purpose multi-agent system module written in Python
https://osbrain.readthedocs.io/en/stable/
Apache License 2.0
175 stars 43 forks source link

agents can't talk to each other #353

Closed yemregundogmus closed 4 years ago

yemregundogmus commented 4 years ago

Greetings, first of all thanks for this excellent library you have created. I am a related person who is just trying to get into the Multi Agent Systems, but I got stuck somewhere and I cannot move forward. I got the code below piece by piece examples and issues.

I have 2 different computers. I want to make one of them a host and the other an agent sending information. I want to do this with osbrain. However, I am facing a problem.

Host Agent is opening the server. 2. My agent connects to the server, but I cannot communicate between the two. Can you help me?

Host_Agent.py

from osbrain import run_nameserver
from osbrain.proxy import locate_ns
from osbrain import run_agent
import osbrain
import time
import pickle

def log_message(agent, message):
    agent.log_info('Received: %s' % message)

if __name__ == '__main__':

    ns_sock = '127.0.0.1:1212'

    osbrain.config['TRANSPORT'] = 'tcp'

    ns_proxy = run_nameserver(ns_sock)
    ns_addr = locate_ns(ns_sock)
    # New Agent

    while True:
        time.sleep(5)
        agents_in_NS = osbrain.nameserver.NameServer.agents(ns_proxy)
        print('Current agents in Nameserver are: %s' %agents_in_NS)

New_Agent.py

from osbrain import NSProxy
from osbrain import run_agent
import osbrain
import Pyro4
import pickle
import time

if __name__ == '__main__':

    ns_addr = '127.0.0.1:1212'

    osbrain.config['TRANSPORT'] = 'tcp'

    ns_proxy = NSProxy(ns_addr)

    print('Registering Agent with server...')
    agent_proxy = run_agent('Agent3', ns_addr)
    address = agent_proxy.bind('PUSH', alias='main')
    time.sleep(5)
    print('I have joined the nameserver!')

    for i in range(1000):
        print("I try to say HEY!")
        agent_proxy.send('main',message='Hey')
        print("I tried")
        time.sleep(2)

    print("Done")
ocaballeror commented 4 years ago

Hi

The issue here is that your agent is not communicating with anybody. You are trying to send a message to the "main" channel, but there is nobody connected to it to receive it, so it will hang forever.

In order for your test to work, you will need a second agent that can listen for that message and then do something with it. Take a closer look at this example in the docs, it is very similar to what you are trying to achieve.

Peque commented 4 years ago

Also, note that you are binding to '127.0.0.1', which is the localhost.

I would suggest you to carefully read through the osBrain documentation to understand how to work with it. Read at least the first 5 sections (from "About osBrain" until "Timers"). Read the Distributed systems section too.

yemregundogmus commented 4 years ago

Hello! After reading the documents you mentioned in detail again, I updated my code a little more, but I still cannot connect the listener bob to name_server.

Host.py

from osbrain import run_nameserver
from osbrain.proxy import locate_ns
from osbrain import run_agent
import osbrain
import time
import pickle

def log_message(agent, message):
    agent.log_info('Received: %s' % message)

if __name__ == '__main__':

    ns_sock = '127.0.0.1:1125'

    osbrain.config['TRANSPORT'] = 'tcp'
    osbrain.config['SERIALIZER'] = 'json'

    ns_proxy = run_nameserver(ns_sock)
    ns_addr = locate_ns(ns_sock)

    # New Agent
    time.sleep(5)
    bob = run_agent('Bob', nsaddr=ns_addr, serializer='json')
    agent_proxy = ns_proxy.proxy('Bob')
    address = agent_proxy.addr('alias1')
    bob.connect(address, handler=log_message)

    while True:
        time.sleep(5)
        agents_in_NS = osbrain.nameserver.NameServer.agents(ns_proxy)
        print('Current agents in Nameserver are: %s' %agents_in_NS)

Agent.py

from osbrain import NSProxy
from osbrain import run_agent
import osbrain
import Pyro4
import pickle
import time

if __name__ == '__main__':

    ns_sock = '127.0.0.1:1125'
    osbrain.config['TRANSPORT'] = 'tcp'
    osbrain.config['SERIALIZER'] = 'json'

    ns_proxy = NSProxy(ns_addr)

    print('Registering Agent with server...')
    alice = run_agent('Alice', ns_addr, serializer='json')
    # Raw serialization will override json for this socket
    addr1 = alice.bind('PUB', 'alias1', serializer='json')
    print('I have joined the nameserver!')

    time.sleep(5)
    for i in range(1000):
        print("I try to say HEY!")
        alice.send('alias1','Hey')
        print("I tried")
        time.sleep(2)

    print("Done")
address = agent.bind('PULL', transport='tcp', addr='127.0.0.1:1234')

I also tried the method you mentioned in distributed systems. However, here I encounter 2 different errors.

Peque commented 4 years ago

@yemregundogmus Couple of random thoughts:

yemregundogmus commented 4 years ago

Greetings,

first of all i'm sorry for throwing code that doesn't work. While working on the Jupyter notebook, I must have sent it with the variables left in memory.

I read the articles you sent, I set up the system as PULL-PUSH and decided to send the message in that way. In this context, I put Alice and Bob on the same network, one in PULL and the other in PUSH. But even if Alice sends a message, Bob cannot hear.

Thank you very much for your patience and support.

Note: I'm bind on localhost to try it right now. I am running 2 different scripts.

Host.py

from osbrain import run_nameserver
from osbrain.proxy import locate_ns
from osbrain import run_agent
import osbrain
import time
import pickle

def log_message(agent, message):
    agent.log_info('Received: %s' % message)

if __name__ == '__main__':

    ns_sock = '127.0.0.1:1129'

    osbrain.config['TRANSPORT'] = 'tcp'
    osbrain.config['SERIALIZER'] = 'json'

    ns_proxy = run_nameserver(ns_sock)
    ns_addr = locate_ns(ns_sock)

    # New Agent

    bob = run_agent('Bob', ns_sock)
    addr1 = bob.bind('SUB', alias='main', handler=log_message)

    print("Setups done, wait for message")

Agent.py

from osbrain import NSProxy
from osbrain import run_agent
import osbrain
import Pyro4
import pickle
import time

if __name__ == '__main__':

    ns_sock = '127.0.0.1:1129'
    osbrain.config['TRANSPORT'] = 'tcp'
    osbrain.config['SERIALIZER'] = 'json'

    print('Registering Agent with server...')
    alice = run_agent('Alice', ns_sock)
    # Raw serialization will override json for this socket
    address = alice.bind('PUB', alias='main')
    print('I have joined the nameserver!')

    for i in range(10):
        print("I try to say HEY!")
        alice.send('main','Hey')
        print("I tried")
        time.sleep(2)

    print("Done")
Peque commented 4 years ago

@yemregundogmus You have not connected those agents.

Read the basic communication patterns documentation to understand how to connect them (see the required .connect() call from one of them). Since you are using a distributed system, read the distributed systems documentation to know how to retrieve an already-running agent's address in order to connect to it.

The resulting code may look like this:

nameserver = NSProxy(ns_sock)
alice.connect(nameserver.proxy('Bob').addr('main'), alias='main')
Peque commented 4 years ago

To be honest, I would use a well-known address for your main communication pattern, instead of binding to a random port. This would allow you to bind after connecting, or recover the host from a crash without the clients even noticing. Otherwise it would be harder for you to handle possible failures.

So just declare your main socket address as a string literal in both scripts, just like you do with the nameserver address.

This is just a suggestion, you can of course go with the default random addresses.

Peque commented 4 years ago

Closing this for now. Feel free to comment/reopen if you need further help. :blush: