def __init__(self, io_udp, addr, name=None): """ Constructor. @parameter io_udp: Main IO. @type io_udp: C{L{IO_UDP}} @parameter addr: The client network address (host, port). @type addr: C{(str, int)} @parameter name: The client name. @type name: C{str} """ io.IO_Client.__init__(self, io_udp, addr, name) self.send_ping = False self.__waitAck = {} self.__received = {} self.__waitAck_sema = thread.allocate_lock() self.__received_sema = thread.allocate_lock() self.__pinger = UDP_Pinger(self)
class UDP_Client(io.IO_Client): """ An UDP Client. @ivar __waitAck: List of packets (id) which are waiting for an acknoledge. @type __waitAck: C{dict<int>, L{Packet<io.Packet>}} @ivar __waitAck_sema: Lock used to access L{__waitAck}. @type __waitAck_sema: C{thread.lock} @ivar __received: List of received packets (id). List used to remove duplicated packets. @type __received: C{dict<int, L{Packet<io.Packet>}>} @ivar __received_sema: Lock used to access L{__received}. @type __received_sema: C{thread.lock} @ivar __pinger: Send regulary ping to server. @type __pinger: C{L{UDP_Pinger}} """ def __init__(self, io_udp, addr, name=None): """ Constructor. @parameter io_udp: Main IO. @type io_udp: C{L{IO_UDP}} @parameter addr: The client network address (host, port). @type addr: C{(str, int)} @parameter name: The client name. @type name: C{str} """ io.IO_Client.__init__(self, io_udp, addr, name) self.send_ping = False self.__waitAck = {} self.__received = {} self.__waitAck_sema = thread.allocate_lock() self.__received_sema = thread.allocate_lock() self.__pinger = UDP_Pinger(self) def alreadyReceived(self, id): """ Tell if a packet (id) is already received. @rtype: C{bool} """ self.__received_sema.acquire() received = id in self.__received self.__received_sema.release() return received def receivePacket(self, packet): """ Process a new received packet. @type packet: C{L{Packet<io.Packet>}} """ if packet.skippable: return # Store packet to drop packet which are receive twice timeout = time.time() + io.Packet.total_timeout self.__received_sema.acquire() self.__received[packet.id] = timeout self.__received_sema.release() def processPing(self, id): """ Process a new received ping. @type id: C{int} """ self.__pinger.processPing(id) def processPong(self, id): """ Process a new received pong. @type id: C{int} """ self.__pinger.processPong(id) def processAck(self, packet): """ Process new received acknoledge. @type packet: C{L{Packet<io.Packet>}} """ # Read packet ID format = "!I" if len(packet.data) != struct.calcsize(format): return None data = struct.unpack(format, packet.data) id = data[0] # Packet still exists ? self.__waitAck_sema.acquire() if not self.__waitAck.has_key(id): self.__waitAck_sema.release() return # Debug message if self.io.debug: t = time.time() - self.__waitAck[id].creation log.info("Ack %u received (time=%.1f ms)" % (id, t * 1000)) # The packet don't need ack anymore del self.__waitAck[id] self.__waitAck_sema.release() def disconnect(self): """ Disconnect client. """ self.io.disconnectClient(self) def needAck(self, packet): """ Tell that a packet needs an acknoledge. """ self.__waitAck_sema.acquire() self.__waitAck[packet.id] = packet self.__waitAck_sema.release() def live(self): """ Keep the connection alive : Resend packet if needed, clean old received packets, send ping if needed. """ # Resend packet which don't have received their ack yet self.__waitAck_sema.acquire() waitAckCopy = self.__waitAck.copy() self.__waitAck_sema.release() for id, packet in waitAckCopy.items(): if packet.timeout < time.time(): if packet.sent < io.Packet.max_resend: self.send(packet) else: self.io.clientLostConnection(self) # Clean old received packets self.__received_sema.acquire() receivedCopy = self.__received.copy() self.__received_sema.release() for id, timeout in receivedCopy.items(): if timeout < time.time(): if self.io.debug: log.info("Remove old packet %u from %s:%u (clear cache)." \ % (id, self.host, self.port)) self.__received_sema.acquire() del self.__received[id] self.__received_sema.release() # Send ping if needed if self.send_ping: self.__pinger.live() def send(self, packet): """ Send packet to the client. """ self.io.send(packet, to=self) def sendBinary(self, data): """ Send binary datas the client. """ self.io.sendBinary(data, self)
class UDP_Client(io.IO_Client): """ An UDP Client. @ivar __waitAck: List of packets (id) which are waiting for an acknoledge. @type __waitAck: C{dict<int>, L{Packet<io.Packet>}} @ivar __waitAck_sema: Lock used to access L{__waitAck}. @type __waitAck_sema: C{thread.lock} @ivar __received: List of received packets (id). List used to remove duplicated packets. @type __received: C{dict<int, L{Packet<io.Packet>}>} @ivar __received_sema: Lock used to access L{__received}. @type __received_sema: C{thread.lock} @ivar __pinger: Send regulary ping to server. @type __pinger: C{L{UDP_Pinger}} """ def __init__(self, io_udp, addr, name=None): """ Constructor. @parameter io_udp: Main IO. @type io_udp: C{L{IO_UDP}} @parameter addr: The client network address (host, port). @type addr: C{(str, int)} @parameter name: The client name. @type name: C{str} """ io.IO_Client.__init__(self, io_udp, addr, name) self.send_ping = False self.__waitAck = {} self.__received = {} self.__waitAck_sema = thread.allocate_lock() self.__received_sema = thread.allocate_lock() self.__pinger = UDP_Pinger(self) def alreadyReceived(self, id): """ Tell if a packet (id) is already received. @rtype: C{bool} """ self.__received_sema.acquire() received = id in self.__received self.__received_sema.release() return received def receivePacket(self, packet): """ Process a new received packet. @type packet: C{L{Packet<io.Packet>}} """ if packet.skippable: return # Store packet to drop packet which are receive twice timeout = time.time()+io.Packet.total_timeout self.__received_sema.acquire() self.__received[packet.id] = timeout self.__received_sema.release() def processPing(self, id): """ Process a new received ping. @type id: C{int} """ self.__pinger.processPing(id) def processPong(self, id): """ Process a new received pong. @type id: C{int} """ self.__pinger.processPong(id) def processAck(self, packet): """ Process new received acknoledge. @type packet: C{L{Packet<io.Packet>}} """ # Read packet ID format = "!I" if len(packet.data) != struct.calcsize(format): return None data = struct.unpack(format, packet.data) id = data[0] # Packet still exists ? self.__waitAck_sema.acquire() if not self.__waitAck.has_key(id): self.__waitAck_sema.release() return # Debug message if self.io.debug: t = time.time() - self.__waitAck[id].creation log.info("Ack %u received (time=%.1f ms)" % (id, t*1000)) # The packet don't need ack anymore del self.__waitAck[id] self.__waitAck_sema.release() def disconnect(self): """ Disconnect client. """ self.io.disconnectClient(self) def needAck(self, packet): """ Tell that a packet needs an acknoledge. """ self.__waitAck_sema.acquire() self.__waitAck[packet.id] = packet self.__waitAck_sema.release() def live(self): """ Keep the connection alive : Resend packet if needed, clean old received packets, send ping if needed. """ # Resend packet which don't have received their ack yet self.__waitAck_sema.acquire() waitAckCopy = self.__waitAck.copy() self.__waitAck_sema.release() for id,packet in waitAckCopy.items(): if packet.timeout < time.time(): if packet.sent < io.Packet.max_resend: self.send(packet) else: self.io.clientLostConnection(self) # Clean old received packets self.__received_sema.acquire() receivedCopy = self.__received.copy() self.__received_sema.release() for id,timeout in receivedCopy.items(): if timeout < time.time(): if self.io.debug: log.info("Remove old packet %u from %s:%u (clear cache)." \ % (id, self.host, self.port)) self.__received_sema.acquire() del self.__received[id] self.__received_sema.release() # Send ping if needed if self.send_ping: self.__pinger.live() def send(self, packet): """ Send packet to the client. """ self.io.send(packet, to=self) def sendBinary(self, data): """ Send binary datas the client. """ self.io.sendBinary(data, self)