def __init__(self,port=None): self.sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # self.sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEPORT, 1)#so any socket can use this port if port is not None: self.sock.bind(('',port)) #stuff for receiving #when received something, put it in the recvMsgsQ #so it can be procesed self.recvMsgsLock = threading.Lock() self.recvMsgsCV = threading.Condition(self.recvMsgsLock) self.recvMsgsQ = Queue.Queue()#a queue of messages available to be returned through recv function #array of packets that are sent and server is waiting for their ACKs self.pendingACKsPacketsLock = threading.Lock() self.pendingACKsPackets = [] self.recvACKs = Dict() #ACKs[addressPortTuple] = [list of ACKs of messages that are received and proccessed] #so when server gets a message it knows wether it was received before so it can safely ignore it self.ACKManager = ACKManager() #manages acks for messages sent self.__startUpWaitingForAcksThread() self.__startUpListeningThread()
class Socket: def __init__(self,port=None): self.sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # self.sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEPORT, 1)#so any socket can use this port if port is not None: self.sock.bind(('',port)) #stuff for receiving #when received something, put it in the recvMsgsQ #so it can be procesed self.recvMsgsLock = threading.Lock() self.recvMsgsCV = threading.Condition(self.recvMsgsLock) self.recvMsgsQ = Queue.Queue()#a queue of messages available to be returned through recv function #array of packets that are sent and server is waiting for their ACKs self.pendingACKsPacketsLock = threading.Lock() self.pendingACKsPackets = [] self.recvACKs = Dict() #ACKs[addressPortTuple] = [list of ACKs of messages that are received and proccessed] #so when server gets a message it knows wether it was received before so it can safely ignore it self.ACKManager = ACKManager() #manages acks for messages sent self.__startUpWaitingForAcksThread() self.__startUpListeningThread() #end init def sendto(self,msg,addressPortTuple): sendThread = threading.Thread(target = self.__sendto,args = (msg,addressPortTuple)) sendThread.name = "sendto"+json.dumps(addressPortTuple) sendThread.start() def __sendto(self,msg,addressPortTuple): """ args: msg: dict addressPortTuple: tuple get the maximum ack number of the list of acks, add 1 to it set that to be the ack of the message being sent put in the list of acks that number return: None """ msg["ack"] = str( self.ACKManager.getACK(addressPortTuple) ) self.sock.sendto(json.dumps(msg),addressPortTuple) # print "Socket||__sendto||"+json.dumps(addressPortTuple),"ack=",msg["ack"] # print "added ",msg["ack"], "to pending" self.pendingACKsPackets.append( Packet( msg, int(msg["ack"]), addressPortTuple, time.time() ) ) # time.sleep(0.5) #end sendto def __startUpWaitingForAcksThread(self): waitingForAcks = threading.Thread(target = self.__waitingForAcks) waitingForAcks.name = "waiting for acks thread" waitingForAcks.start() def __waitingForAcks(self): """ a function to be ran in a thread this function is meant to keep looping an array of Packets if 0.5 seconds have passed on any msg it resends it and resets the lastTimeSent it uses the ack of the message to check in ACKManager if it was confirmed (we know it was confirmed through the __listen) arrayToBeLooped is the array gonna be looped on everytime self.pendingACKsPackets is the global array whenever server sends something it appends it to this array """ arrayToBeLooped = [] packetsNotConfirmed = [] while True: #add anything pending from outside self.pendingACKsPacketsLock.acquire() arrayToBeLooped += self.pendingACKsPackets self.pendingACKsPackets = [] self.pendingACKsPacketsLock.release() packetsNotConfirmed = []# reset local array of loop for packet in arrayToBeLooped: if self.ACKManager.isACKConfirmed(packet.addressPortTuple,packet.ack): # print "got the ack: ", packet.ack continue if time.time() - packet.lastTimeSent >=0.5: print "didn't get the ack sending again: "+str(packet.ack)+str(packet.msg) self.sock.sendto(json.dumps(packet.msg), packet.addressPortTuple) packet.lastTimeSent=time.time() packetsNotConfirmed.append(packet) #end of for arrayToBeLooped = packetsNotConfirmed #end of while #end __waitingForAcks def recvfrom(self,buffer=1024): with self.recvMsgsCV:# while self.recvMsgsQ.empty():# just wait while its empty # print "Socket||recvfrom||waiting for a new msg" self.recvMsgsCV.wait() # print "Socket||recvfrom||done waiting for a new msg" msg,addressPortTuple = self.recvMsgsQ.get() #done with self.recvMsgsCV return msg,addressPortTuple #end recv def __listen(self): while True: # print "Socket||__listen||waiting for new msg" recv,addressPortTuple = self.sock.recvfrom(1024) try: recvJ = json.loads(recv) except: # print "Socket||__listen||got non json object:"+recv recvJ = {"msg": recv} if recvJ.get("msg","") == "ack": # I'm receiving an ack to a message I sent # print "Socket||__listen||im receiving an ack" self.ACKManager.confirmACK(addressPortTuple,int(recvJ["ack"])) continue else:# then it's a message intended to me, I better reply to it #first: just send the ack print "Socket||__listen||sending ACK back,to this msg:"+str(recvJ) if "ack" not in recvJ.keys(): continue sendJ={ "msg": "ack", "ack": recvJ["ack"] } self.sock.sendto(json.dumps(sendJ),addressPortTuple) #second: see if we already have it just skip ... we don't want to process it twice, do we? if addressPortTuple in self.recvACKs.keys() and recvJ["ack"] in self.recvACKs.get(addressPortTuple): # print "Socket||__listen||we already have that, Skipping..." continue #third: oh, looks like it wasn't processed before, we better mark it as proccessed then if addressPortTuple not in self.recvACKs.keys(): self.recvACKs.put(addressPortTuple,[ recvJ["ack"] ] ) else: self.recvACKs.get(addressPortTuple).append( recvJ["ack"] ) #fourth: and of course, put it in the processing queue with self.recvMsgsCV: self.recvMsgsQ.put( (recv,addressPortTuple) ) self.recvMsgsCV.notify() #now go back in the loop again! #end __listen def __startUpListeningThread(self): listenThread = threading.Thread(target = self.__listen) listenThread.name = "listenForAllMessages" listenThread.start() #end __startUpListeningThread #end class Socket