From 1c285786adb2893b7557d2f4b89c0566c79602f7 Mon Sep 17 00:00:00 2001 From: Artem30801 Date: Sat, 19 Jan 2019 20:45:07 +0300 Subject: [PATCH] Import and name fix --- Drone/{Client.py => client.py} | 4 +- Server/{Server.py => server.py} | 578 ++++++++++++++++---------------- 2 files changed, 291 insertions(+), 291 deletions(-) rename Drone/{Client.py => client.py} (99%) mode change 100755 => 100644 rename Server/{Server.py => server.py} (96%) diff --git a/Drone/Client.py b/Drone/client.py old mode 100755 new mode 100644 similarity index 99% rename from Drone/Client.py rename to Drone/client.py index 8b1a7b5..304115f --- a/Drone/Client.py +++ b/Drone/client.py @@ -8,9 +8,9 @@ import threading import ConfigParser from contextlib import closing -#import rospy +import rospy -#import play_animation +import play_animation random.seed() diff --git a/Server/Server.py b/Server/server.py similarity index 96% rename from Server/Server.py rename to Server/server.py index e23082f..8711a49 100644 --- a/Server/Server.py +++ b/Server/server.py @@ -1,289 +1,289 @@ -from tkinter import * -from tkinter import ttk -from tkinter import filedialog -import ttkwidgets - -import os -import sys -import glob -import time -import struct -import socket -import threading -import collections -import configparser - -# All imports sorted in pyramid - - -def auto_connect(): - while True: - ServerSocket.listen(1) - c, addr = ServerSocket.accept() - print("Got connection from:", str(addr)) - #client_thread = threading.Thread(target=on_new_client, args=(c, addr)) - #client_thread.start() - - if not any(client_addr == addr[0] for client_addr in Client.clients.keys()): - client = Client(addr[0]) - print("New client") - else: - print("Reconnected client") - Client.clients[addr[0]].connect(c, addr) - - -NTP_DELTA = 2208988800 # 1970-01-01 00:00:00 -NTP_QUERY = b'\x1b' + bytes(47) - - -def get_ntp_time(ntp_host, ntp_port): - with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s: - s.sendto(NTP_QUERY, (ntp_host, ntp_port)) - msg, _ = s.recvfrom(1024) - return int.from_bytes(msg[-8:], 'big') / 2 ** 32 - NTP_DELTA - - -def requires_connect(f): - def wrapper(*args, **kwargs): - if args[0].connected: - return f(*args, **kwargs) - else: - print("Function requires client to be connected!") - return wrapper - - -class Client: - clients = {} - - def __init__(self, ip): - self.socket = None - self.addr = None - - self._send_queue = collections.deque() - self._received_queue = collections.deque() - self._request_queue = collections.OrderedDict() - - self.copter_id = None - self.malfunction = False - - Client.clients[ip] = self - - self.connected = False - - def connect(self, client_socket, client_addr): - print("Client connected") - self._send_queue = collections.deque() # comment for resuming queue after reconnection - - self.socket = client_socket - self.addr = client_addr - - self.socket.setblocking(0) - self.connected = True - client_thread = threading.Thread(target=self._run, args=()) - client_thread.start() - if self.copter_id is None: - self.copter_id = self.get_response("id") - print("Got copter id:", self.copter_id) - drone_list.insert("", "end", self.addr[0], text=self.copter_id) - - def _send_all(self, msg): - self.socket.sendall(struct.pack('>I', len(msg)) + msg) - - def _receive_all(self, n): - data = b'' - while len(data) < n: - packet = self.socket.recv(min(n - len(data), BUFFER_SIZE)) - if not packet: - return None - data += packet - return data - - def _receive_message(self): - raw_msglen = self._receive_all(4) - if not raw_msglen: - return None - msglen = struct.unpack('>I', raw_msglen)[0] - msg = self._receive_all(msglen) - return msg - - def _run(self): - while self.connected: - try: - if self._send_queue: - msg = self._send_queue.popleft() - print("Send", msg, "to", self.addr) - self._send_all(msg) - else: - msg = "ping" - #self._send_all(msg) - - try: # check if data in buffer - check = self.socket.recv(BUFFER_SIZE, socket.MSG_PEEK) - if check: - received = self._receive_message() - if received: - received = received.decode("UTF-8") - print("Recived", received, "from", self.addr) - command, args = Client.parse_command(received) - if command == "response": - for key, value in self._request_queue.items(): - if not value: - self._request_queue[key] = args[0] - print("Request successfully closed") - break - else: - self._received_queue.appendleft(received) - except socket.error: - pass - - except socket.error as e: - print("Client error, disconnected", e) - self.connected = False - self.socket.close() - break - # time.sleep(0.05) - - @staticmethod - def form_command(command: str, args=()): # Change for different protocol - return " ".join([command, *args]) - - @staticmethod - def parse_command(command_input): - args = command_input.split() - command = args.pop(0) - return command, args - - @requires_connect - def send(self, *messages): - for message in messages: - self._send_queue.append(bytes(message, "UTF-8")) - - @staticmethod - def broadcast(message, force_all=False): - for client in Client.clients.values(): - if (not client.malfunction) or force_all: - client.send(message) - - @requires_connect - def send_file(self, filepath, dest_filename): - print("Sending file ", dest_filename) - self.send(Client.form_command("writefile", (dest_filename,))) - file = open(filepath, 'rb') - chunk = file.read(BUFFER_SIZE) - while chunk: - self._send_queue.append(chunk) - chunk = file.read(BUFFER_SIZE) - file.close() - self.send(Client.form_command("/endoffile")) - print("File sent") - - @requires_connect - def get_response(self, requested_value): - self._request_queue[requested_value] = "" - self.send(Client.form_command("request", (requested_value, ))) - - while not self._request_queue[requested_value]: - pass - - return self._request_queue.pop(requested_value) - - -# UI functions -def stop_swarm(): - Client.broadcast("stop") # для тестирования - - -def send_animations(): - path = filedialog.askdirectory(title="Animation directory") - if path: - print("Selected directory:", path) - files = [file for file in glob.glob(path+'/*.csv')] - names = [os.path.basename(file).split(".")[0] for file in files] - print(files) - for file, name in zip(files, names): - for copter in Client.clients.values(): - if name == copter.copter_id: - copter.send_file(file, "animation.csv") # TODO config - else: - print("Filename not matches with any drone connected") - #dr = next(iter(Client.clients.values())) # костыль для тестирования - #ANS = dr.get_response("someshit") - #print(ANS) - - -def send_starttime(dt=60): - timenow = time.time() - print('Now:', time.ctime(timenow), "+ dt =", dt) - Client.broadcast(Client.form_command("starttime", (str(timenow+dt), ))) - - -# UI build here -root = Tk() -root.wm_title("Drone swarm operation server") -root.style = ttk.Style() -root.style.theme_use("vista") - -leftFrame = Frame(root) -leftFrame.grid(row=0, column=0, padx=10, pady=10) -rightFrame = Frame(root) -rightFrame.grid(row=0, column=1, padx=10, pady=10) - -drone_list = ttkwidgets.CheckboxTreeview(leftFrame, columns=("addr", "connected")) -#drone_list["columns"] = ("addr") -#drone_list.column("name") #width=100 -#drone_list.column("addr") -drone_list.heading("#0", text="Drone name") -drone_list.heading("#1", text="Connection adress") -drone_list.heading("#2", text="Connection status") -drone_list.pack() - -button_frame = Frame(leftFrame, borderwidth=1, relief="solid") -button_frame.pack(fill=BOTH, expand=True) - -stop_all_btn = ttk.Button(button_frame, text="Stop swarm", command=stop_swarm) -stop_all_btn.pack(side=RIGHT, padx=5, pady=5) - -send_animation_btn = ttk.Button(button_frame, text="Send animations", command=send_animations) -send_animation_btn.pack(side=RIGHT, padx=5, pady=5) - -send_starttime_btn = ttk.Button(button_frame, text="Start animation after...", command=send_starttime) -send_starttime_btn.pack(side=RIGHT, padx=5, pady=5) - - -def gui_update(): - time.sleep(0.1) - - -# reading config -config = configparser.ConfigParser() -config.read("server_config.ini") - -port = int(config['SERVER']['port']) -BUFFER_SIZE = int(config['SERVER']['buffer_size']) -NTP_HOST = config['NTP']['host'] -NTP_PORT = int(config['NTP']['port']) - - -ServerSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # socket.socket() # -ServerSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) -host = socket.gethostname() -ip = socket.gethostbyname_ex(host)[-1] - -print('Server started on', host, ip, ":", port) -#print('Now:', time.ctime(get_ntp_time(NTP_HOST, NTP_PORT))) -print('Waiting for clients...') -ServerSocket.bind((ip[-1], port)) - -autoconnect_thread = threading.Thread(target=auto_connect) -autoconnect_thread.daemon = True -autoconnect_thread.start() - - -if __name__ == '__main__': - try: - mainloop() - except KeyboardInterrupt: - print("Stopping server by keyboard interrupt") - finally: - ServerSocket.close() - print("Server shutdown") +from tkinter import * +from tkinter import ttk +from tkinter import filedialog +import ttkwidgets + +import os +import sys +import glob +import time +import struct +import socket +import threading +import collections +import configparser + +# All imports sorted in pyramid + + +def auto_connect(): + while True: + ServerSocket.listen(1) + c, addr = ServerSocket.accept() + print("Got connection from:", str(addr)) + #client_thread = threading.Thread(target=on_new_client, args=(c, addr)) + #client_thread.start() + + if not any(client_addr == addr[0] for client_addr in Client.clients.keys()): + client = Client(addr[0]) + print("New client") + else: + print("Reconnected client") + Client.clients[addr[0]].connect(c, addr) + + +NTP_DELTA = 2208988800 # 1970-01-01 00:00:00 +NTP_QUERY = b'\x1b' + bytes(47) + + +def get_ntp_time(ntp_host, ntp_port): + with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s: + s.sendto(NTP_QUERY, (ntp_host, ntp_port)) + msg, _ = s.recvfrom(1024) + return int.from_bytes(msg[-8:], 'big') / 2 ** 32 - NTP_DELTA + + +def requires_connect(f): + def wrapper(*args, **kwargs): + if args[0].connected: + return f(*args, **kwargs) + else: + print("Function requires client to be connected!") + return wrapper + + +class Client: + clients = {} + + def __init__(self, ip): + self.socket = None + self.addr = None + + self._send_queue = collections.deque() + self._received_queue = collections.deque() + self._request_queue = collections.OrderedDict() + + self.copter_id = None + self.malfunction = False + + Client.clients[ip] = self + + self.connected = False + + def connect(self, client_socket, client_addr): + print("Client connected") + self._send_queue = collections.deque() # comment for resuming queue after reconnection + + self.socket = client_socket + self.addr = client_addr + + self.socket.setblocking(0) + self.connected = True + client_thread = threading.Thread(target=self._run, args=()) + client_thread.start() + if self.copter_id is None: + self.copter_id = self.get_response("id") + print("Got copter id:", self.copter_id) + drone_list.insert("", "end", self.addr[0], text=self.copter_id) + + def _send_all(self, msg): + self.socket.sendall(struct.pack('>I', len(msg)) + msg) + + def _receive_all(self, n): + data = b'' + while len(data) < n: + packet = self.socket.recv(min(n - len(data), BUFFER_SIZE)) + if not packet: + return None + data += packet + return data + + def _receive_message(self): + raw_msglen = self._receive_all(4) + if not raw_msglen: + return None + msglen = struct.unpack('>I', raw_msglen)[0] + msg = self._receive_all(msglen) + return msg + + def _run(self): + while self.connected: + try: + if self._send_queue: + msg = self._send_queue.popleft() + print("Send", msg, "to", self.addr) + self._send_all(msg) + else: + msg = "ping" + #self._send_all(msg) + + try: # check if data in buffer + check = self.socket.recv(BUFFER_SIZE, socket.MSG_PEEK) + if check: + received = self._receive_message() + if received: + received = received.decode("UTF-8") + print("Recived", received, "from", self.addr) + command, args = Client.parse_command(received) + if command == "response": + for key, value in self._request_queue.items(): + if not value: + self._request_queue[key] = args[0] + print("Request successfully closed") + break + else: + self._received_queue.appendleft(received) + except socket.error: + pass + + except socket.error as e: + print("Client error, disconnected", e) + self.connected = False + self.socket.close() + break + # time.sleep(0.05) + + @staticmethod + def form_command(command: str, args=()): # Change for different protocol + return " ".join([command, *args]) + + @staticmethod + def parse_command(command_input): + args = command_input.split() + command = args.pop(0) + return command, args + + @requires_connect + def send(self, *messages): + for message in messages: + self._send_queue.append(bytes(message, "UTF-8")) + + @staticmethod + def broadcast(message, force_all=False): + for client in Client.clients.values(): + if (not client.malfunction) or force_all: + client.send(message) + + @requires_connect + def send_file(self, filepath, dest_filename): + print("Sending file ", dest_filename) + self.send(Client.form_command("writefile", (dest_filename,))) + file = open(filepath, 'rb') + chunk = file.read(BUFFER_SIZE) + while chunk: + self._send_queue.append(chunk) + chunk = file.read(BUFFER_SIZE) + file.close() + self.send(Client.form_command("/endoffile")) + print("File sent") + + @requires_connect + def get_response(self, requested_value): + self._request_queue[requested_value] = "" + self.send(Client.form_command("request", (requested_value, ))) + + while not self._request_queue[requested_value]: + pass + + return self._request_queue.pop(requested_value) + + +# UI functions +def stop_swarm(): + Client.broadcast("stop") # для тестирования + + +def send_animations(): + path = filedialog.askdirectory(title="Animation directory") + if path: + print("Selected directory:", path) + files = [file for file in glob.glob(path+'/*.csv')] + names = [os.path.basename(file).split(".")[0] for file in files] + print(files) + for file, name in zip(files, names): + for copter in Client.clients.values(): + if name == copter.copter_id: + copter.send_file(file, "animation.csv") # TODO config + else: + print("Filename not matches with any drone connected") + #dr = next(iter(Client.clients.values())) # костыль для тестирования + #ANS = dr.get_response("someshit") + #print(ANS) + + +def send_starttime(dt=60): + timenow = time.time() + print('Now:', time.ctime(timenow), "+ dt =", dt) + Client.broadcast(Client.form_command("starttime", (str(timenow+dt), ))) + + +# UI build here +root = Tk() +root.wm_title("Drone swarm operation server") +root.style = ttk.Style() +root.style.theme_use("vista") + +leftFrame = Frame(root) +leftFrame.grid(row=0, column=0, padx=10, pady=10) +rightFrame = Frame(root) +rightFrame.grid(row=0, column=1, padx=10, pady=10) + +drone_list = ttkwidgets.CheckboxTreeview(leftFrame, columns=("addr", "connected")) +#drone_list["columns"] = ("addr") +#drone_list.column("name") #width=100 +#drone_list.column("addr") +drone_list.heading("#0", text="Drone name") +drone_list.heading("#1", text="Connection adress") +drone_list.heading("#2", text="Connection status") +drone_list.pack() + +button_frame = Frame(leftFrame, borderwidth=1, relief="solid") +button_frame.pack(fill=BOTH, expand=True) + +stop_all_btn = ttk.Button(button_frame, text="Stop swarm", command=stop_swarm) +stop_all_btn.pack(side=RIGHT, padx=5, pady=5) + +send_animation_btn = ttk.Button(button_frame, text="Send animations", command=send_animations) +send_animation_btn.pack(side=RIGHT, padx=5, pady=5) + +send_starttime_btn = ttk.Button(button_frame, text="Start animation after...", command=send_starttime) +send_starttime_btn.pack(side=RIGHT, padx=5, pady=5) + + +def gui_update(): + time.sleep(0.1) + + +# reading config +config = configparser.ConfigParser() +config.read("server_config.ini") + +port = int(config['SERVER']['port']) +BUFFER_SIZE = int(config['SERVER']['buffer_size']) +NTP_HOST = config['NTP']['host'] +NTP_PORT = int(config['NTP']['port']) + + +ServerSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # socket.socket() # +ServerSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) +host = socket.gethostname() +ip = socket.gethostbyname_ex(host)[-1] + +print('Server started on', host, ip, ":", port) +#print('Now:', time.ctime(get_ntp_time(NTP_HOST, NTP_PORT))) +print('Waiting for clients...') +ServerSocket.bind((ip[-1], port)) + +autoconnect_thread = threading.Thread(target=auto_connect) +autoconnect_thread.daemon = True +autoconnect_thread.start() + + +if __name__ == '__main__': + try: + mainloop() + except KeyboardInterrupt: + print("Stopping server by keyboard interrupt") + finally: + ServerSocket.close() + print("Server shutdown")