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:
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