#!/usr/bin/env python3 """Socket Client implementation (TCP or UDP) """ # Standard library imports import socket # Third party imports # None # Local application imports from devices_controller.channels.client_channel import * ##class SocketClientAbstract(): class ClientChannelSocket(ClientChannel): # Select protocol here (udp or tcp) buf = 1024 mysock = None # STAMP : # 00 00 00 00 00 00 00' (8 bytes from '00' to 'FF', 1st one is LOW BYTE) # ex: 01 + STAMP = 01 00 00 00 00 00 00 00' (8 bytes from '00' to 'FF', 1st one is LOW BYTE) #STAMP_FILLER = '00000000000000' ''' STAMP_FILLER = '000000' MYSTAMP = '01' MY_FULL_STAMP = MYSTAMP + STAMP_FILLER ''' def __init__(self, server_host:str="localhost", server_port:int=11110, PROTOCOL:str="SOCKET-TCP", buffer_size=1024, DEBUG=False): ''' :param server_host: server IP or hostname :param server_port: server port :param PROTOCOL: "SOCKET-UDP" or "SOCKET-TCP" ''' myprotocol = socket.SOCK_DGRAM if PROTOCOL=="SOCKET-UDP" else socket.SOCK_STREAM self.mysock = socket.socket(socket.AF_INET, myprotocol) super().__init__(server_host, server_port, PROTOCOL, buffer_size, DEBUG) # Logger configuration #self.set_logger() ''' log_d("\n**************************") log_d("Logger configured") log_d("Client instanciated") ''' ''' def _send_data(self, data_to_send:str): #data_to_send = bytes(data_to_send + "\n", "utf-8") #data_to_send = bytes(data_to_send + "\x00", "utf-8") ##data_to_send = bytes(data_to_send, "utf-8") #print("before sending", data_to_send) data_to_send_bytes = data_to_send.encode("utf-8") #data_to_send_bytes = data_to_send.encode() #print("before sending", data_to_send_bytes) if self.PROTOCOL=="SOCKET-TCP": # Unlike send(), this method sendall() continues to send data from bytes until either all data has been sent or an error occurs. # None is returned on success. # On error, an exception is raised, and there is no way to determine how much data, if any, was successfully sent nb_bytes_sent = self.mysock.sendall(data_to_send_bytes) else: nb_bytes_sent = self.mysock.sendto(data_to_send_bytes, (self.HOST, self.PORT)) log_i(f'Sent: {data_to_send_bytes}') log_i(f"Sent {nb_bytes_sent} bytes") ''' ''' def _receive_data(self)->bytes: data_received = self.mysock.recv(self.buf) #log_d("data type is "+str(type(data_received))) log_i(f"RECEIVED (ALL BYTES): {data_received}") #return str(data_received, "utf-8") return data_received ''' # Only for TCP ; does nothing for UDP #@override def _connect_to_server(self): if self.PROTOCOL=="SOCKET-TCP": self.mysock.connect((self.HOST, self.PORT)) print(f"Ready to send commands to HOST {self.HOST} on PORT {self.PORT} \n") # Close socket def close(self): self.mysock.close() #@override def _send_data(self, data_to_send:str): #data_to_send = bytes(data_to_send + "\n", "utf-8") #data_to_send = bytes(data_to_send + "\x00", "utf-8") ##data_to_send = bytes(data_to_send, "utf-8") data_to_send_bytes = data_to_send.encode("utf-8") #data_to_send_bytes = data_to_send.encode() if self.PROTOCOL=="SOCKET-TCP": # Unlike send(), this method sendall() continues to send data from bytes until either all data has been sent or an error occurs. # None is returned on success. # On error, an exception is raised, and there is no way to determine how much data, if any, was successfully sent nb_bytes_sent = self.mysock.sendall(data_to_send_bytes) else: # SOCKET-UDP nb_bytes_sent = self.mysock.sendto(data_to_send_bytes, (self.HOST, self.PORT)) log_i(f'Sent: {data_to_send_bytes}') log_i(f"Sent {nb_bytes_sent} bytes") #@override def _receive_data(self)->str: data_received_bytes = self.mysock.recv(self.buf) #TODO: resoudre ce pb plus proprement (utiliser unicode au lieu de utf-8 codec ??? # BUGFIX: b'\xdf' (should correspond to "°" symbol) generates a UnicodeDecodeError, # so, replace it by ':' (b'\x3A') if b'\xdf' in data_received_bytes: data_received_bytes = data_received_bytes.replace(b'\xdf', b'\x3A') log_i(f"RECEIVED (ALL BYTES): {data_received_bytes}") data_received = data_received_bytes.decode() #log_d("data type is "+str(type(data_received))) #return str(data_received, "utf-8") return data_received ''' # Encapsulate useful data to be ready for sending #@override def encapsulate_data_to_send(self, data:str): #return bytes(data, "utf-8") return data.encode("utf-8") # Extract data from received raw data #@override def uncap_received_data(self, data_received_bytes:bytes): #return data_received.decode("utf-8) return data_received_bytes.decode() ''' # TODO: empecher de creer une instance de cette classe abstraite # Avec ABC ? ''' if __name__ == "__main__": #HOST, PORT = "localhost", 9999 #HOST, PORT = "localhost", 20001 HOST, PORT = "localhost", 11110 # Classic usage: #tsock = SocketClient_UDP_TCP(HOST, PORT, "UDP") # More elegant usage, using "with": with SocketClient_ABSTRACT(HOST, PORT, "UDP") as tsock: # 0) CONNECT to server (only for TCP, does nothing for UDP) tsock._connect_to_server() while True: # 1) SEND REQUEST data to server # saisie de la requête au clavier et suppression des espaces des 2 côtés data = input("REQUEST TO SERVER [ex: ':GD#' (Get Dec), ':GR#' (Get RA)']: ").strip() # test d'arrêt if data=="": break #data_to_send = bytes(data + "\n", "utf-8") tsock.send_data(data) #mysock.sendto("%s" % data, (HOST, PORT)) #print("Sent: {}".format(data)) # 2) RECEIVE REPLY data from server data_received = tsock.receive_data() #reponse, adr = mysock.recvfrom(buf) #print("Received: {}".format(data_received)) #print("Useful data received: {}".format(data_useful)) print('\n') #tsock.close() '''