A Simple Peer-to-peer Network in Python twisted

Source: Internet
Author: User
Tags uuid in python

Let's do a simple Peer-to-peer network in Python. It should be able to discover the other nodes and ping them over the network. We are using twisted for building the network.

I mostly used the Bitcoin Developer documentation to teach me how to write a Peer-to-peer network. I wrote an implementation of the model described this in BENEDIKTKR/NCPOC.

Since this are a peer-to-peer network, every instance has to be both the a server and a client. The the clients need some way to find all other, and recognize itself in the event it tried to connect to it self. UUID to identify peers

Since outgoing TCP connections are assigned random ports, we cannot rely on Ip:port as identifies for instances of the Peer-to-peer Network. We are going assign each instance a random UUID for the session. A UUID is 128 bits, seems like a reasonably small overhead.

>>> from UUID import uuid4
>>> Generate_nodeid = Lambda:str (Uuid4 ())
' A46de8d6-177e-4644-a711-63d182fdbade '
defining a simple protocol in Twisted

We'll only have talk about Twisted to the extent of that are nessacary to builds this. For more information on how to builds servers and protocols with twisted, writing servers in the Twisted Documenation is a Good place to start.

The Factory class instance is persistent between connections, so it's where we store things like the peer list and the Uui D for this session. A new instance of Myfactoryis created for each connection.

From twisted.internet.endpoints import tcp4serverendpoint
from twisted.internet.protocol Import protocol, Factory From
twisted.internet Import reactor

class MyProtocol (Protocol):
    def __init__ (self, Factory):
        Self.factory = Factory
        Self.nodeid = Self.factory.nodeid

class MyFactory (Factory):
    def startfactory (self ):
        self.peers = {}
        Self.nodeid = Generate_nodeid ()

    def buildprotocol (self, addr): Return
        Ncprotocol (self)
        
Endpoint = Tcp4serverendpoint (reactor, 5999)
Endpoint.listen (MyFactory ())

This would define a listener for a completely empty protocol on localhost:5999. Not very useful so far. We want the nodes to be able to send each other messages and taalk. We'll use JSON-strings to create the messages, it's easy to serialize and very readable.

Let's begin by creating a hello message for the new nodes to introduce themselves. We are also include what kind of a message it are, so peers can easily the out I to figure it.

{
    ' Nodeid ': ' A46de8d6-177e-4644-a711-63d182fdbade ', '
    msgtype ': ' Hello ',
}

Now we are need to edit our code to is handle getting a hello from a new conncetion. We also need to keep a list of connected UUIDs (the Peers property of the Factory class.

Import JSON class MyProtocol (Protocol): Def __init__ (self, factory): Self.factory = Factory Self.stat
        E = "HELLO" Self.remote_nodeid = None Self.nodeid = Self.factory.nodeid def connectionmade (self): Print "Connection from", Self.transport.getPeer () def connectionlost (self, Reason): if Self.remote_n Odeid in Self.factory.peers:self.factory.peers.pop (self.remote_nodeid) print Self.nodeid, "disconnect
            Ed "Def DataReceived" (Self, data): For line in Data.splitlines (): line = Line.strip () if self.state = = "HELLO": Self.handle_hello (line) self.state = "READY" def Send_hello
   
    (self): Hello = json.puts ({' Nodeid ': Self.nodeid, ' msgtype ': ' Hello '}) self.transport.write (hello + "\ n")
        def handle_hello (self, hello): hello = json.loads (hello) Self.remote_nodeid = hello["Nodeid"] If Self.remote_nodeiD = = Self.nodeid:print "Connected to myself." Self.transport.loseConnection () Else:self.factory.peers[self.remote_nodeid] = self

This'll be capable of the sending and reading a Hello message, and keep track of connected peers. talking to the Protocol

So-we have something that looks like a "server" thats able to handle a hello message. We need to make this also act as a "client". The Twisted is a nice-batteries included library, the so is almost for free with Twisted ' s callbacks.

From twisted.internet.endpoints import Tcp4clientendpoint, Connectprotocol

def gotprotocol (p): "" "" "
    Callback to start the Protocol exchange. We let connecting
    nodes start of the Hello handshake "" " 
    P.send_hello () point

= Tcp4clientendpoint (Reactor," localhost ", 5999)
d = Connectprotocol (point, MyProtocol ())
D.addcallback (Gotprotocol)
Bootstrapping the network

If we run both of those parts, a succesful handshake'll hopefully be performed and the listening would output som Ething like

Connection from 127.0.0.1:58790
Connected to myself. 
A46de8d6-177e-4644-a711-63d182fdbade disconnected.

We need more than one instance to have a Peer-to-peer network. The simplest way to get the the the the "the" the "the" the "the" "the" "Network to find", "simply" a "," have Host:port Ations and then initially loop through this list and try connecting to them, starting all instance with a different Liste Ning Port.

Bootstrap_list = ["localhost:5999"
                 , "localhost:5998"
                 , "localhost:5997"] for

BOOTSTRAP in Bootstrap_list :
    host, port = Bootstrap.split (":") point
    = Tcp4clientendpoint (reactor, host, int (port))
    d = Connectprotocol (Point, MyProtocol ())
    D.addcallback (gotprotocol)
Reactor.run ()

-and now we can bootstrap a network with a couple of different instances to our program. Ping

Let's make them does something useful and add a ping message with a empty payload. We also need a pong message for the response.

{
     ' msgtype ': ' Ping ',
}
{
    ' msgtype ': ' Pong ',
}

When we send a ping to a connected node, we do so when we got the pong reply. This is useful to detect dead clients, and gives we simple ping/pong message flow some purpose. We also use Twisted ' s loopingcall to ping nodes on a regular interval. Since each connection has it's own MyProtocol instance, we don ' t have to loop over all of them, we can do in the Abstra Ction of connections.

Again, twisted does most of the heavy-lifting for us. Edit the MyProtocol class to operate the mechanics.

 from time import twisted.internet.task import Loopingcall class M 
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.