peer-2-peer network: now with diagrams!

General discussion about LÖVE, Lua, game development, puns, and unicorns.
Post Reply
User avatar
togFox
Party member
Posts: 764
Joined: Sat Jan 30, 2021 9:46 am
Location: Brisbane, Oztralia

peer-2-peer network: now with diagrams!

Post by togFox »

I'd like to set up an adhoc p2p network of Love2D 'agents' that has no central server, and allows agents to drop in and join that network adhoc.

For experimental purposes, the Agent can join the network, send and receive 'chat' messages (e.g. social network), and then disconnect. Messages sent while disconnected are lost.

I'm thinking of using gossip protocol to disseminate messages. Speed, performance and reliability are not important.

An Agent that joins the network would first join to an advertised or known node. This node might change overtime and might be advertised on DISCORD or TWITTER or whatever. Point is, you can't join the network until you have a known entry point.

Getting to the real question: using love2d enet, how would I establish hosts/clients if I want every agent to connect at least three neighbours so the gossip protocol can be effective?

Bonus question: once the Agent first joins, how should they discover other neighbours, join with those neighbours and strengthen the gossip protocol?

I have spent the last few days looking into enet, sockets, grease etc so I'm no expert but I think I know the basics. All the tutorials show one client connecting to one server. I'm after many clients connecting to many other clients (no server).
Last edited by togFox on Sun Apr 25, 2021 1:48 am, edited 1 time in total.
Current project:
https://togfox.itch.io/backyard-gridiron-manager
American football manager/sim game - build and manage a roster and win season after season
User avatar
tomxp411
Prole
Posts: 29
Joined: Thu Apr 08, 2021 5:41 pm

Re: peer-2-peer network?

Post by tomxp411 »

Here's what I would do...
  • Each node in the mesh would maintain a list of all the known peers, with a unique ID, Name, IP address, Status (Online, Offline, Dead) and Last Seen (timestamp).
  • The IP address can change, but the ID should not. The ID should be procedurally generated and unique for every machine. This allows you to track nodes as they change IP addresses.
  • When a peer connects in to the mesh, it will announce itself to the contacted node, then ask for a list of known nodes.
  • The new peer will announce to the other nodes on the list, along with any other nodes it already knows about.
  • When any node receives an announce, it will update its registry with the IP address and Last Seen timestamp.
  • When a node shuts down, it will broadcast a shutdown message to all of the peers it knows about. When a peer receives a shutdown message, it will set status to Down.
  • Nodes will need to send an "I'm here" message to all of the nodes on the network periodically. Let's call it 15 minutes. After 2 intervals (30 minutes), mark a node as Offline. After a longer period (a week?) mark a node as "Dead" and do not propagate it to new nodes.
  • Finally, it may be that some nodes can't contact another directly. You'll want to develop a relay system for that - but you should not try to do this for your initial prototype; just getting your mesh talking 1:1 will have its own challenges.
As far as working with multiple nodes via enet... you need multiple "server" objects in a table, where each server is a known peer on the mesh. As you receive announce messages or get a list at startup, you'll append new nodes to the list or update existing nodes...

although, I'd just use UDP and skip enet entirely. You can use udp:receivefrom() to read incoming packets, then deal with the packets based either on ID data inside the packet or just the IP address.

here are a couple of stupid simple programs I wrote while trying to figure out Lua sockets...

This program just waits for incoming data and displays the results...

Code: Select all

local socket = require("socket")

local udp = assert(socket.udp())
udp:setsockname("*",1234)
udp:settimeout(30)

local data = nil
while true do
-- retrieve the answer and print results
	data,ip,status = udp:receivefrom()
	if data then
		print(data,ip,status)
	end
end
and this just transmits a number every two seconds...

Code: Select all

local host, port = "127.0.0.1", 1234
local socket = require("socket")
local udp = assert(socket.udp())

udp:settimeout(30)

local i = 1
while true do
	print(i)
	udp:sendto(tostring(i), ip, port)
	socket.sleep(2)
	i=i+1
end
User avatar
togFox
Party member
Posts: 764
Joined: Sat Jan 30, 2021 9:46 am
Location: Brisbane, Oztralia

Re: peer-2-peer network?

Post by togFox »

Wow. This is a great response. It seems so few people know or care about this stuff. Let me break some of this down:

- my (not very good) prototype has a simple list of known nodes. It captures IP/Port and a user-provided name. It would ultimately store the clients UUID as well. Easy. With simple logic that manages nodes, users and endpoints.

- peer connecting and announcing. Yep. enet detects a 'connect' and then my prototype clients immediately 'send' their UUID/name etc. Got that. Done. Same page.

- the new peer getting the list of nodes and announcing itself was not what I thought - but it's good. My slight variation is the node that received the new node will broadcast the new node. Same I guess. I just thought a message about a newcomer should come from a node that is already known and registered. I'll worry about that later.

- timestamps and shutdowns. Yep. Makes sense. Same page. I was going to monitor for "no response" and consider a threshold for offline and dead.

- relay system: see my original post about gossip protocols. I was thinking each node would know of up to ~5 other nodes (or whatever number) and would send and receive to just those known neighbours and let the gossip messages filter across the network.

Keeping a list of just 5 neighbours (arbitrary number) would make the network more scalable as nodes are added. I wasn't sure how to do that with enet. Each node would need to be a client and a server (a true P2P network where no node is better than another node) so I was thinking that each client needs one server to listen to all neighbours and then perhaps 5 client connections to 5 different servers. That right? That means I'd need 1 server object and 5 clients in a table/list/array. Not sure how to do that.

Thanks for your code. I'm going to try that to see if I can get that to work reliably. :)
Current project:
https://togfox.itch.io/backyard-gridiron-manager
American football manager/sim game - build and manage a roster and win season after season
User avatar
pgimeno
Party member
Posts: 3541
Joined: Sun Oct 18, 2015 2:58 pm

Re: peer-2-peer network?

Post by pgimeno »

In a decentralized system, you still need to have a centralized server in order to bootstrap. Kademlia and DHT work like that; you need a list of known clients to start with.
User avatar
togFox
Party member
Posts: 764
Joined: Sat Jan 30, 2021 9:46 am
Location: Brisbane, Oztralia

Re: peer-2-peer network?

Post by togFox »

If the clients are doing nothing other than listening for new nodes, registering those new nodes, and then 'gossiping' text messages then would there be nothing to bootstrap? In other words, the network starts with just one node and can't do anything meaningful until another joins. At this point, the two nodes are aware of each other and an exchange of text messages can begin.

There doesn't seem to be anything to bootstrap.
Current project:
https://togfox.itch.io/backyard-gridiron-manager
American football manager/sim game - build and manage a roster and win season after season
User avatar
pgimeno
Party member
Posts: 3541
Joined: Sun Oct 18, 2015 2:58 pm

Re: peer-2-peer network?

Post by pgimeno »

If someone needs to enter the IP of another node to connect to, then that's a manual bootstrapping. If many nodes just stand idle waiting for connections, there's no network.
User avatar
togFox
Party member
Posts: 764
Joined: Sat Jan 30, 2021 9:46 am
Location: Brisbane, Oztralia

Re: peer-2-peer network?

Post by togFox »

Yes. I see.

My intention is to have a inputbox for manual entry that will be cached and saved for next time. Of course, IP's change so that inputbox will forever have a purpose.
Current project:
https://togfox.itch.io/backyard-gridiron-manager
American football manager/sim game - build and manage a roster and win season after season
User avatar
togFox
Party member
Posts: 764
Joined: Sat Jan 30, 2021 9:46 am
Location: Brisbane, Oztralia

Re: peer-2-peer network?

Post by togFox »

I'm trying to nut out how a client would perform in a server role and a client role in one app. I did a bit of a workflow for how that would work.

Basic workflow:

- the app starts up and immediately creates a 'host' and starts listening. Super easy and a pre-condition to the network starting.

- a second app is started and starts listening

- the first app discovers the IP address of the second app (inputbox), registers that IP on it's own "node list" and sends a connect request. It's important to not that the first app is now acting as a client, whilst still listening as a host.

- the second app receives the connection request but with enet nothing really happens other than a connection (no information is known to the host)

- with enet, the first app (as a client) can now send the IP it is using to listen to (the host).

- the second app (still in 'host' mode) receives that new information now has knowledge of two listeners (hosts). It updates it's internal node list accordingly.

- the second app now needs to reciprocate the connection but can't do that in host mode so it invokes it's 'client' code to request a client connection back to the first app.

- the first app is satisfied that a two-way client/host connection is established and falls back to 'host' mode. It is ready to receive it's own connections and grow the network.

- the second app, in host mode, has a big responsibility. It has discovered and allowed a new connection so it needs to 'gossip' it's node list to the rest of the network so those nodes are away of the first app and can gossip back and the network ties are strengthened.

This diagram shows one app (only one!) and the sequence of events and how it transitions from host to client and back to host again.

This is all due to the one way client -> host connection that UDP supports - or am I over-complicating this? A node, at any given time, needs to do two things - send messages to hosts whilst being ready to receive messages from clients - remembering - a true peer-to-peer network where all nodes are equal.

Am I over complicating this?


Image
Current project:
https://togfox.itch.io/backyard-gridiron-manager
American football manager/sim game - build and manage a roster and win season after season
Post Reply

Who is online

Users browsing this forum: No registered users and 19 guests