Revista Do Linux
 
  
  
 

  Capa
  Evento
  Serviço Público
  Corporativo
  Tutorial ECF Remota
  Tutorial Xdm
  Software
  Entrevista
  Estudo de Caso
  Distro
assinantes
 

Como montar uma impressora fiscal remota

Veja como executar sua aplicação de automação comercial em uma rede de estações Linux com um servidor de impressão

Sua aplicação roda no servidor, e é executada remotamente via telnet ou ssh. O problema que surge é que a aplicação tenta usar a impressora fiscal conectada à porta serial do computador em que está sendo executada, mas a impressora está conectada a outra estação.

A solução é rodar um daemon na estação remota que vai esperar conexões do servidor que executa a aplicação de automação comercial, ouvindo em uma determinada porta. O servidor de impressora fiscal remota funciona da seguinte maneira:

  • O daemon fica ouvindo uma determinada porta à espera de uma conexão;
  • Estabelecida a conexão, são recebidos os dados destinados à impressora fiscal ;
  • Os dados são passados ao driver da impressora fiscal;
  • O retorno da impressora é enviado de volta ao computador que roda a aplicação comercial;
  • A conexão é fechada e o daemon volta a esperar novas conexões.

    Instalação

    A instalação deste servidor de ECF remota leva em conta que o driver da ECF é do tipo executável externo à aplicação e recebe seus dados através de arquivos. Caso não seja este o caso e o driver seja do tipo biblioteca de funções, você deverá construir uma aplicação que se comporte como este tipo de driver. Escrever uma aplicação deste tipo é uma tarefa extremamente simples para quem programou a aplicação de automação comercial. Se você mesmo é o desenvolvedor da aplicação, mãos à obra, caso contrário, não aceite desculpas do desenvolvedor alegando complexidade do problema ou necessidade bem maior de tempo.

    1)Instale o driver da impressora fiscal;

    2)Edite o arquivo servidorecf.py (veja listagem abaixo) para que os caminhos para arquivos e binários correspondam ao seu sistema;

    3)Certifique-se de que o caminho para o driver da ECF está correto;

    4)Copie o arquivo servidorecf.py para o diretório em que residirá;

    5)Inclua a seguinte linha no arquivo /etc/inittab para iniciar automaticamente o servidor:

    ecf:2345:respawn:/usr/sbin/servidorecf.py
    

    Veja no quadro 1 a listagem do código fonte do daemon servidor de ECF remota, escrito em Python, que deverá ser instalado na estação remota. Note que alguns parâmetros precisam ser ajustados ao seu sistema. Você precisará criar também algumas hierarquias de diretórios adicionais para abrigar os arquivos temporários de comandos e de resultados ou poderá ajustar o código do servidor de ECF para usar outra hierarquia existente no seu sistema.

    Veja também que o servidor tem um esquema de autenticação do cliente baseado em strings que são apresentadas e esperadas no início da conexão. Novamente, se você prevê problemas com segurança na sua rede interna, pode mudar isto para técnicas de autenticação mais robustas, até com algoritmos criptográficos.

    Apesar de o código apresentado aqui ter qualidade de produção, é interessante que você o entenda e revise para ter maior controle e entendimento sobre o processo. Você vai notar que é um código simples e fácil de usar.

    Configuração do cliente

    Instale o programa cliente no computador que acessará a impressora fiscal. Você pode renomear o driver original e substituí-lo pelo programa cliente ou modificar a aplicação para que invoque o cliente de ECF remota no lugar do driver original.

    A aplicação deverá executar o programa cliente passando como parâmetros o endereço IP da estação que tem a impressora fiscal, o arquivo que contém os comandos para a ECF, o arquivo que deverá conter a resposta da ECF e o arquivo que receberá o status da ECF.

    Note que tanto o daemon do servidor quanto o programa cliente são facilmente adaptáveis para que mandem e recebam os dados necessários à ECF na seqüência e quantidade necessárias. O código deste exemplo atende à maioria das impressoras disponíveis no mercado, mas novas situações podem surgir:

    Caso você tenha interesse em aprender mais sobre a tecnologia usada na aplicação servidor de ECF, veja, em www.python.org, documentação sobre como usar sockets no Python.

    Atenção!

    O servidor de ECF será instalado na estação de trabalho na qual está conectada a impressora fiscal. Tenha todo cuidado para não confundir servidor com cliente, já que a estação cliente executará uma aplicação servidora e o servidor executará uma aplicação cliente.

    Quadro 1 - Código fonte do arquivo servidorecf.py

    #!/usr/bin/python
    
    ## servidorecf.py
    ## Servidor para ECF remota
    ## Ricardo Alexandre Mattar
    ## .
    
    import os
    import socket
    import curses.ascii
    
    lf = chr(curses.ascii.LF)
    
    ## Inicio da configuração
    
    host = 'localhost'
    port = 8000
    
    ## constantes de protocolo
    
    identificacaoservidor = 'servidor ecf' + lf
    enviocomandoecf = 'enviocomandoecf'
    enviarstatus = 'enviarstatus'
    enviarretorno = 'enviarretorno'
    fechar = 'fechar'
    
    ## parametros do binario ecf
    
    arqcomandoecf = '/var/run/ecf/comandoecffinal'
    arqrespostaecf = '/var/run/ecf/respostaecforiginal'
    arqstatusecf = '/var/run/ecf/statusecf'
    binarioecf = '/usr/local/bin/binecf'
    
    ## Fim da configuração
    
    flagfechar = 0
    
    while 1:
            try:
                    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                    s.bind((host,port))
                    s.listen(1)
                    conn, addr = s.accept()
            except socket.error:
                    continue
            while 1:
                    try:
                            conn.send(identificacaoservidor)
                    except socket.error:
                            break
                    while 1:
                            try:
                                    data = conn.recv(1024)
                            except socket.error:
                                    break
    
                            if data[:len(enviocomandoecf)] == enviocomandoecf:
                                    try:
                                            data = conn.recv(1024)
                                    except socket.error:
                                            break
                                    # grave no arquivo final
                                    comandosecf = open(arqcomandoecf,'w')
                                    comandosecf.write(data)
                                    comandosecf.flush()
                                    comandosecf.close()
                                    # invoque o driver da ecf
                                    os.spawnl(os.P_WAIT,  
                                    binarioecf, binarioecf,
                                    arqcomandoecf,                                                  
    				arqrespostaecf,                                                         
    				arqstatusecf)
    
                            elif data[:len(enviarstatus)] == enviarstatus:
                                    statusecf = open(arqstatusecf,'r')
                                    data = statusecf.read()
                                    statusecf.close()
                                    try:
                                            conn.send(data + lf)
                                    except socket.error:
                                            break
    
                            elif data[:len(enviarretorno)] == enviarretorno:
                                    respostaecf = open(arqrespostaecf,'r')
                                    data = respostaecf.read()
                                    respostaecf.close()
                                    try:
                                            conn.send(data + lf)
                                    except socket.error:
                                            break
    
                            elif (data[:len(fechar)] == fechar) or not data:
                                    flagfechar = 1
                                    break
                    if flagfechar:
                            conn.close()
                            break
            conn.close()
    

    Quadro 2 - Listagem de programa cliente para ECF remota

    #!/usr/bin/python
    ##
    ## Cliente para ECF remota
    ##
    ## Ricardo Alexandre Mattar 
    ##
    ## uso:
    ##
    ## ecfremota.py  
    ##  
    ## ou modifique configuração mais abaixo e coloque
    ## os parametros hard-coded
    ## e chame ecfremota.py 
    
    import os
    import sys
    import socket
    import curses.ascii
    
    lf = chr(curses.ascii.LF)
    
    ## Inicio da configuração            ##
    
    # Endereço do servidor deve ser passado como
    ## parametro ou...
    #host = 127.0.0.1
    host = sys.argv[1]
    port = 8000
    
    ## constantes de protocolo
    identificacaoservidor = 'servidor ecf' + lf
    identificacaocliente = 'reqecf' + lf
    enviocomandoecf = 'enviocomandoecf' + lf
    enviarstatus = 'enviarstatus' + lf
    enviarretorno = 'enviarretorno' + lf
    fechar = 'fechar' + lf
    
    #arqcomandoecf = '/var/ecf/comandoecforiginal'
    #arqrespostaecf = '/var/ecf/respostaecffinal'
    #arqstatusecf = '/var/ecf/statusecffinal'
    
    arqcomandoecf = sys.argv[2]
    arqrespostasecf = sys.argv[3]
    arqstatusecf = sys.argv[4]
    
    ## Fim da configuração               ##
    
    ## Conecte-se ao servidor
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((host, port))
    
    ## Identifique-se
    s.send(identificacaocliente)
    data = s.recv(1024)
    ## e verifique se é o servidor desejado
    if data == identificacaoservidor:
            ## leia os comandos para a ecf no arquivo
            comandoecf = open(arqcomandoecf,'r')
            data = comandoecf.read()
            comandoecf.close()
            ## e envie  para o servidor ecf
            s.send(enviocomandoecf)
            s.send(data)
    
            ## receba o status
            s.send(enviarstatus)
            data = s.recv(1024)
            ## e grave no arquivo
            statusecf = open(arqstatusecf,'w')
            ## [:-1] remove o lf enviado pelo servidor
            statusecf.write(data[:-1])
            statusecf.flush()
            statusecf.close()
    
            ##receba a resposta
            s.send(enviarrestorno)
            data = s.recv(1024)
            ## e grave no arquivo
            respostaecf = open(arqrespostaecf,'w')
            ## [:-1] remove o lf enviado pelo servidor
            respostaecf.write(data[:-1])
            respostaecf.flush()
            respostaecf.close()
    
    s.close()
    

    Ricardo Alexandre Mattar - ricardo.mattar@bol.com.br

  • A Revista do Linux é editada pela Conectiva S/A
    Todos os Direitos Reservados.

    Política de Privacidade
    Anuncie na Revista do Linux