示例#1
0
class McastParams(object):
    """ Esta classe armazena e retorna alguns parametros e funcoes comuns ao
    cliente e servidor multicast. O objetivo principal eh evitar redundancia
    de codigo """
    def __init__(self,port,addr,sbound="",sport=None):

        self.__port = int(port)
        self.__addr = addr
        self.__serverbound = sbound
        self.__serverport = sport or int(port)-1
        self.__log = Log()
        self.__quit = False

    def quit(self):
        """ Mata threads, se existirem """
        if self.getThread():
            os.kill(self.getThreadPID(),signal.SIGKILL)
            self.closeSocket()

    def shouldQuit(self):
        return self.__quit

    def closeSocket(self):
        self.getSocket().close()

    def getSocket(self):
        return self.__socket

    def getPort(self):
        return self.__port

    def getAddr(self):
        return self.__addr

    def writeLog(self, v, msg):
        self.__log.log(v,"Mcast:%s"%msg)

    def getServerBound(self):
        return self.__serverbound

    def getServerPort(self):
        return self.__serverport

    def setThreadPID(self,pid):
        self.__threadPID = pid

    def getThreadPID(self):
        return self.__threadPID

    def read(self):
        while True:
            try:
                return self.getSocket().recvfrom(1024)
            except socket.error, errormsg:
                self.writeLog(LOGERROR,"read")
示例#2
0
def waitrequest(*args):
    """ Executa funcao "handle" para cada mensagem recebida.
        Funcao executada em uma thread separada """

    obj, handle = args[0], args[1]
    obj.setThreadPID(os.getpid())
    log = Log()
    while not obj.shouldQuit():
        try:
            handle(obj.read())
        except socket.error,errormsg:
            log.log(LOGERROR,"watrequest:%s"%errormsg)
            pass
        time.sleep(0.01)
示例#3
0
class OnlineCalcServer(McastServiceServer,Thread):
    def __init__(self, serverID, mcastPort, mcastAddr, serverFile):

        Thread.__init__(self)
        McastServiceServer.__init__(self,mcastPort,mcastAddr)
        self.__serverDict = self.readServerFile(serverFile)
        self.__server = int(serverID)
        self.__requestList = []
        self.__timeoutList = []
        self.__log = Log("server%d.log"%self.__server)
        self.writeLog(LOGCONTROL,"Iniciando...")

        self.getServer().setAlive()

        # Sinaliza quando a thread tera que ser fechada
        self.__quit = False

    def run(self):
        """ Este metodo recebe as mensagens e endereca para o metodo
        correto """

        # Criando timeout para o heartbeat
        self.__createTimeout(self.sendHeartBeat,TOUT_HEARTBEAT)
        # Criando timeout para o atualizar status dos servidores
        self.__createTimeout(self.updateHeartBeat,TOUT_DEAD)

        while not self.__quit:
            (data,(ip,port)) = self.getRequest()
            Thread(target=self.parserRequest,args=(data,ip,port)).start()

    def parserRequest(self, data, ip, port):
        """ Recebe uma requisicao e faz o parser executando os metodos
        necessarios. """

        # Expressoes regulares de possiveis mensagens
        reID = "(?P<id>[0-9]+)"
        rePORT = "(?P<port>[0-9]{4,5})"
        reREQCONF = "(?P<request>.*)"
        reREQ = "(?P<request>[0-9()\.\+\-\/\*]*)"

        reALIVE = re.compile("^%s:ALIVE$" % reID)
        reCONFIRM = re.compile("%s:CONFIRM:%s$" % (reID,reREQCONF))
        reREQUEST = re.compile("^%s:%s$"%(rePORT,reREQ))
        reQUIT = re.compile("^%s:QUIT$"% reID)

        if reALIVE.match(data):
            data = reALIVE.search(data)
            sid = int(data.group("id"))
            self.heartBeatReceived(sid)
        elif reCONFIRM.match(data):
            data = reCONFIRM.search(data)
            serverID = data.group("id")
            request = Request(data.group("request"))
            self.requestSentby(serverID,request)
        elif reREQUEST.match(data):
            data = reREQUEST.search(data)
            port = data.group("port")
            data = "%s:%s:%s" %(ip,port,data.group("request"))
            request = Request(data)
            self.addRequest(request)
            self.sendReply(request)
        elif reQUIT.match(data):
            data = reQUIT.search(data)
            serverID = int(data.group("id"))
            self.serverQuiting(serverID)
        else:
            msg = "Request invalido (%s,%d):%s"%(ip,port,data)
            self.writeLog(LOGWARNING,msg)

    def __createTimeout(self,method,tout):
        tout = Timeout(method,tout)
        tout.start()
        self.addTimeout(tout)

    def serverQuiting(self, serverID):
        """ Quando um servidor vai sair seta ele como morto """
        if self.getServer() != self.getServerDict()[serverID]:
            msg = "Servidor %d desconectou"%( serverID )
            self.writeLog(LOGCONTROL,msg)
            self.missingHeartBeat(serverID)

    def readServerFile(self,serverFile):
        """ Le um arquivo contendo os servidores que serao utilizados e
        retorna um dicionario {id:Server} """

        serverList = {}
        for line in open(serverFile):
            # Se a linha nao eh um comentario nem vazia
            if not re.match("^(#|$)",line):
                sid,shostname,sport = line.split()
                serverList[int(sid)] = Server(sid,shostname,sport)

        return serverList

    def writeLog(self,verbose,msg):
        """ Escreve uma mensagem no log """
        msg = "Server-%d %s"%( self.getServer().getID(),msg )
        self.__log.log(verbose,msg)

    def addTimeout(self,obj):
        self.__timeoutList.append(obj)

    def addRequest(self, request):
        """ Adiciona uma nova requisicao a lista e a trata """

        self.writeLog(LOGMESSAGE,"Request:%s"%request)
        self.__requestList.append(request)

    def removeRequest(self, request):
        """ Remove request da lista """
        if request in self.__requestList:
            self.__requestList.remove(request)

    def requestSentby(self, serverID, request):
        """ Confirmacao de que o servidor serverID respondeu a requisicao
        request, que deve ser removida da lista """
        if int(serverID) != self.getServer().getID():
            msg = "Servidor %s Respondeu %s"%(serverID,request)
        else:
            msg = "Respondi %s"%(request)
        self.writeLog(LOGMESSAGE,msg)
        self.removeRequest(request)

    def heartBeatReceived(self,serverID):
        """ Marca servidor serverID como vivo """
        if serverID != self.getServer().getID():
            self.writeLog(LOGCONTROL,"HeartBeatReceived:%d"%serverID)
        self.getServerDict()[int(serverID)].setAlive()

    def updateHeartBeat(self):
        """ Verifica se algum servidor nao responde a mais de TOUT_DEAD
        segundos """
        for server in self.getServerDict().values():
            if server != self.getServer():
                if time.time() - server.getLastContact() > TOUT_DEAD:
                    self.missingHeartBeat(server.getID())

    def missingHeartBeat(self,serverID):
        """ Marca servidor serverID como morto """
        self.writeLog(LOGCONTROL,"MissingHeartBeat:%d"%serverID)
        self.getServerDict()[int(serverID)].setNotAlive()

    def sendHeartBeat(self):
        """ Envia mensagem ao multicast informando que esta vivo """
        self.getMcast().send("%d:ALIVE"%self.getServer().getID())

    def whoAnswers(self):
        """ Retorna o menor servidor ativo """
        for idx in sorted(self.getServerDict().keys()):
            server = self.getServerDict()[idx]
            if server.imalive():
                return self.getServerDict()[idx]

    def sendReply(self,request,force=False):
        """ Computa request e (se sou o servidor com menor ID vivo)
        envia resposta para o cliente, ao mesmo tempo
        que comunica os outros servidores do grupo multicast que a
        requisicao request foi respondida. """
        willAnswer = self.whoAnswers()
        if force or willAnswer == self.getServer():
            reply = "Server%d "%(self.getServer().getID())
            reply += str((self.getServer().getAddr()))+": "
            try:
                reply += str(eval(request.getRequest()))
            except (SyntaxError,TypeError),error:
                reply += "ERRO: "+str(error)
            except ZeroDivisionError:
                reply = "ERRO: Ocorreu uma divisao por zero."
            self.writeLog(LOGCONTROL,"Respondendo %s = %s"%(request,reply))
            host,port = request.getIP(),request.getPort()
            McastServiceServer.sendReply(self,host,port,reply)
            self.sendReplyConfirm(request)