-
Notifications
You must be signed in to change notification settings - Fork 4
/
p2p.py
117 lines (95 loc) · 3.5 KB
/
p2p.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import asyncore
import socket
import logging
# https://github.com/nicolargo/pythonarena/blob/master/asyncore/portscan.py
# TODO: find_peers function, which scans available port range and asks other peers which peers it knows about
# TODO: Better interface for working with overall p2p client.
#
# import p2p
#
# peer = p2p.connect("localhost", (55560, 55580))
# peer.find_peers()
# peers = peer.get_peers()
# peer.message("Hello World")
# peer.onMessage((msg) => { console.log(msg); })
#
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
HOST = "localhost"
PORT_RANGE = range(55568, 55578)
class EchoClient(asyncore.dispatcher):
def __init__(self, host, port_range):
asyncore.dispatcher.__init__(self)
self.host = host
self.port_range = port_range
self.buffer = b"HELLO WORLD"
self.reconnect()
def reconnect(self):
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
for port in self.port_range:
try:
self.log("Attempting to connect to %s:%d" % (self.host, port))
self.connect((self.host, port))
self.port = port
self.log("Looks like host is available")
return
except Exception as e:
self.log("Error connecting to %s:%d" % (self.host, port))
def handle_connect(self):
self.log("Successfully connected to %s:%d" % (self.host, self.port))
def writeable(self):
return (len(self.buffer) > 0)
def handle_read(self):
data = self.recv(1024)
if data:
self.log("Received '%s' from SERVER" % (data,))
def handle_write(self):
if self.buffer:
self.log("Sending '%s' to SERVER" % self.buffer)
sent = self.send(self.buffer)
self.buffer = self.buffer[sent:]
def handle_close(self):
self.log("Closed connection to %s:%d" % (self.host, self.port))
self.close()
self.host = None
self.port = None
def log(self, msg):
logging.info("CLIENT: %s", msg)
class EchoHandler(asyncore.dispatcher_with_send):
def handle_read(self):
data = self.recv(8192)
if data:
logging.info("SERVER: Received '%s' from CLIENT" % data)
logging.info("SERVER: Sending '%s' to CLIENT" % data)
self.send(data)
class EchoServer(asyncore.dispatcher):
def __init__(self, host, port_range):
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.host = host
self.set_reuse_addr()
for port in port_range:
if self.attempt_connect(port):
break
self.listen(5)
def attempt_connect(self, port):
try:
self.bind((self.host, port))
self.port = port
self.log("Server found open port and launched on %s:%d" % (self.host, port))
return True
except OSError:
self.log("Port %d is already being used" % (port,))
except:
print("Exception")
return False
def handle_accept(self):
pair = self.accept()
if pair is not None:
sock, addr = pair
self.log("Incoming connection from %s" % repr(addr))
handler = EchoHandler(sock)
def log(self, msg):
logging.info("SERVER: %s", msg)
server = EchoServer(HOST, PORT_RANGE)
client = EchoClient(HOST, PORT_RANGE)
asyncore.loop()