diff --git a/config.py b/config.py index 5872a32..cfbb941 100644 --- a/config.py +++ b/config.py @@ -1,2 +1,4 @@ -MULTICAST_PORT = 10000 -MULTICAST_IP = '224.0.0.1' \ No newline at end of file +MULTICAST_PORT = 10001 +MULTICAST_IP = '224.0.0.1' +TCP_PORT = 10001 +SERVER_IP = 'localhost' \ No newline at end of file diff --git a/daemon_file.py b/daemon_file.py index 62d635e..2adccad 100644 --- a/daemon_file.py +++ b/daemon_file.py @@ -1,9 +1,31 @@ import logging +import socket +import config +import json +import struct +import threading import time import os from daemon import runner from datetime import datetime +client_base = { "clients": + [ + { + "address": "192.168.0.1", + "port": "2208", + "nickname": "nikita", + "online": True + }, + { + "address": "192.168.0.2", + "port": "2208", + "nickname": "pobeda", + "online": False + }, + ] +} + class App(): def __init__(self): @@ -12,15 +34,64 @@ def __init__(self): self.stderr_path = '/dev/null' self.pidfile_path = os.path.join(os.getcwd(), 'multiproto.pid') self.pidfile_timeout = 5 - + def run(self): while True: # logger.debug("Debug message") # logger.info("Info message") # logger.warn("Warning message") # logger.error("Error message") - logger.info(f'LOG: {datetime.now()}') - time.sleep(5) + # logger.info(f'LOG: {datetime.now()}') + self.multicast_handler() + + @staticmethod + def tcp_handler(client_address): + # TCP socket creation + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.connect(client_address) + + # convert dict structure to bytes + msg = json.dumps(client_base).encode('utf-8') + + try: + sock.sendall(msg) + finally: + print('closing socket') + sock.close() + pass + + def multicast_handler(self): + server_address = ('', config.MULTICAST_PORT) + + # UDP socket creation + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + # bind to the server address + sock.bind(server_address) + + # IP string to bytes conversion + mcast_group = socket.inet_aton(config.MULTICAST_IP) + # listen on all interfaces `socket.INADDR_ANY` + mreq = struct.pack('4sL', mcast_group, socket.INADDR_ANY) + sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) + + # Receive/respond loop + while True: + print('\nwaiting to receive message') + logger.info(f'Listening for multicast messages') + data, address = sock.recvfrom(1024) + + print('received %s bytes from %s' % (len(data), address)) + logger.info(f'Received multicast message from {address}') + print(data) + + print('sending acknowledgement to', address) + logger.info(f'Starting TCP session with {address}') + # call TCP session + thread = threading.Thread(target=self.tcp_handler, args=address) + # run thread in the background as daemon + thread.daemon = True + thread.start() + # sock.sendto(json.dumps(client_base).encode('utf-8'), address) if __name__ == '__main__': diff --git a/multicast_client.py b/multicast_client.py index 8481557..0b1d6af 100644 --- a/multicast_client.py +++ b/multicast_client.py @@ -2,13 +2,51 @@ import struct import sys import config +import json +import threading message = 'SERVER DISCOVERY' multicast_group = (config.MULTICAST_IP, config.MULTICAST_PORT) + +def tcp_handler(): + sock_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + server_address = (config.SERVER_IP, config.TCP_PORT) + sock_tcp.bind(server_address) + + sock_tcp.listen(1) + + while True: + # Wait for a connection + print('waiting for a connection') + connection, client_address = sock.accept() + try: + print(sys.stderr, 'connection from', client_address) + + # Receive the data in small chunks and retransmit it + while True: + data = connection.recv(16) + print('received "%s"' % data) + if data: + print('sending data back to the client') + connection.sendall(data) + else: + print('no more data from', client_address) + break + finally: + # Clean up the connection + connection.close() + + +thread = threading.Thread(target=tcp_handler, args=()) +# run thread in the background as daemon +# thread.daemon = True +thread.start() + # Create the datagram socket sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + # Set a timeout so the socket does not block indefinitely when trying # to receive data. sock.settimeout(0.2) @@ -28,13 +66,15 @@ while True: print('waiting to receive') try: - data, server = sock.recvfrom(16) + data, server = sock.recvfrom(1024) except socket.timeout: print('timed out, no more responses') break else: - print('received "%s" from %s' % (data, server)) + res_dict = json.loads(data.decode('utf-8')) + print(res_dict) finally: print('closing socket') sock.close() + # sock_tcp.close() diff --git a/multicast_server.py b/multicast_server.py index b35357b..a316ec2 100644 --- a/multicast_server.py +++ b/multicast_server.py @@ -2,6 +2,24 @@ import struct import sys import config +import json + +client_base = { "clients": + [ + { + "address": "192.168.0.1", + "port": "2208", + "nickname": "nikita", + "online": True + }, + { + "address": "192.168.0.2", + "port": "2208", + "nickname": "pobeda", + "online": False + }, + ] +} server_address = ('', config.MULTICAST_PORT) @@ -11,8 +29,7 @@ # Bind to the server address sock.bind(server_address) -# Tell the operating system to add the socket to the multicast group -# on all interfaces. +# Tell the operating system to add the socket to the multicast group on all interfaces. mcast_group = socket.inet_aton(config.MULTICAST_IP) mreq = struct.pack('4sL', mcast_group, socket.INADDR_ANY) # listen on all interfaces `socket.INADDR_ANY` sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) @@ -26,4 +43,4 @@ print(data) print('sending acknowledgement to', address) - sock.sendto(bytes('ack', encoding='utf-8'), address) + sock.sendto(json.dumps(client_base).encode('utf-8'), address)