25 de outubro de 2021

Do bit Ao Byte

Embarcados, Linux e programação

Socket server com Python

arrays dinâmicos em C++ | Interagir com ponteiros | Alocação de memória | Ponteiros em C/C++ | Socket server com ESP8266 | Socket server com ESP32 | Socket server com Python | Socket client com ESP32 | Sistema de arquivos no ESP8266

Os artigos posteriores serão bastante relacionados a rede, de modo que se fará necessário um certo apoio para testar as implementações. Nada mais fácil do que fazer um socket server com Python para esses testes, uma vez que, além de ser multiplataforma, é fácil e rápido de implementar. Se não quiser fazer nada em seu sistema nativo, pode optar por criar um virtualenv para esses testes.

Por que usar socket server com Python?

Imagine que você precise implementar uma comunicação socket em algum embarcado. A parte essencial de qualquer implementação é a capacidade de testar o que está sendo implementado. Implementar simultaneamente as duas “pontas” da comunicação pode ser caótico, pois em caso de falha fica difícil determinar em qual dos dois lados estará o problema. Executando um socket server local nos garante ter um lado da comunicação garantida e o melhor – poderemos ler os dados como chegam, para no fim fazer a melhor implementação possível.

Uma sugestão (e opinião pessoal) é que não devemos nos ater a uma só linguagem. Se você só programa em C ou C++, acabará ficando refém de uma solução de terceiros, sem a garantia de que ela seja funcional ou adequada (ou até ambos) para seu projeto. Programo relativamente bem em Python desde 2009 (já programei melhor, quando fazia parte do meu dia-a-dia), assim como programo bem o suficiente em C, C++ e Qt (sendo que Qt também não faz mais parte do meu dia-a-dia). Além disso, tenho uma boa habilidade em shellscript (em Linux), e essas linguagens me permitem criar soluções completas multiplataforma e em diversos níveis de serviço. E para quem programa em C/C++, Python acaba sendo extremamente mais simples, como a exemplo desse socket server:

import socket

s = socket.socket()         
 
s.bind(('0.0.0.0', 8888 ))
s.listen(0)                 
 
while True:
    client, addr = s.accept()

    while True:
        content = client.recv(32)
        if len(content) == 0:
           break
        else:
            print(content)
    print("Fim da conexao")
    client.close()

Para testar seu socket server com Python, crie um socket client com a mesma simplicidade:

#!/usr/bin/env python
import socket 

#ip a se conectar
ip = "192.168.1.200"

#porta do socket server
port = 8888 

addr = ((ip,port)) 

client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
client_socket.connect(addr) 

msg = "hell low word"
client_socket.send(msg.encode('UTF-8')) 

client_socket.close()

E o resultado deve ser semelhante a esse:

Socket server com Python

Agora é só acompanhar os próximos artigos relacionados – e deixo o convite para inscrever-se em nosso canal DobitaobyteBrasil no Youtube, com nosso formato de áudio e vídeo, para uma melhor experiência!

Teremos alguns vídeos relacionados à comunicação socket, acredito que vale experimentar.

Dica extra 1: encode e decode

Reparou que o resultado foi impresso na saída como b’hell low word’? Isso significa que a saída está em bytes. Para ter a saída em texto plano, simplesmente utilize .decode(‘UTF-8’) para decodificar a entrada que está no mesmo formato. Claro, existem montes de outros tipo como ISO8859-1, que já foi nosso padrão, mas aqui temos o tipo reconhecido no client. Em suma, a linha que exibe a mensagem no server deve ficar assim:

print(content.decode('UTF-8'))

Dica extra 2: enviar bytes

E se for para enviar bytes invés de char? Simples também: use bytearray(). Apenas no client, faça isso:

#!/usr/bin/env python
import socket 

#ip a se conectar
ip = "192.168.1.200"

#porta do socket server
port = 8888 

addr = ((ip,port)) 

client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
client_socket.connect(addr) 

#exemplo de um array de bytes a enviar
msg = bytearray()
msg.append(94)
msg.append(0xff)
msg.append(1)
msg.append(0)
msg.append(0)
msg.append(0x0a)

client_socket.send(msg) 

client_socket.close()

Assim a mensagem vai toda de uma vez já no formato que usaremos no robô da MASUGUX. Mas isso deixarei para detalhar no próprio artigo do robô.

Dica extra 3: Enviar bytes para o ESP8266

Se for enviar do computador para o ESP8266 ou ESP32, duas considerações: não feche o socket imediatamente após o envio, senão o ESP8266 abortará. Para isso, coloque um delay antes de fechar a conexão. A outra consideração é que não devemos enviar o bytearray ou truncará. Nesse caso, devemos fazer um loop do tamanho do array e passar cada índice. Para saber o tamanho do array, use a função len(seuArrayDeBytes). Com o loop e o delay inclusos, o código fica assim:

#!/usr/bin/env python
import socket 
import time 


#ip a se conectar
ip = "192.168.1.208"

#porta do socket server
port = 123 

addr = ((ip,port)) 

client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
client_socket.connect(addr) 

msg = bytearray()
msg.append(94)
msg.append(0xff)
msg.append(1)
msg.append(0)
msg.append(0)
msg.append(0x0a)

print(len(msg))

for i in range(6):
   client_socket.send(str(msg[i]).encode())

time.sleep(1)

client_socket.close()

Dica extra 4: usando chr

Podemos usar chr para interação, e talvez seja até melhor – porém, usando chr teremos um char assinalado, ou seja, de -127 à 127.

#!/usr/bin/env python
import socket 
import time 
import struct

#ip a se conectar
ip = "192.168.1.208"

#porta do socket server
port = 123 

addr = ((ip,port)) 

client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
client_socket.connect(addr) 

msg = bytearray()
msg.append(94)
msg.append(126)
msg.append(1)
msg.append(0)
msg.append(0)
msg.append(10)

for i in range(6):
    client_socket.send(chr(msg[i]).encode())


time.sleep(1)

client_socket.close()

Para teste está bom.

Boas dicas, hum? Até a próxima!

 

Revisão: Ricardo Amaral de Andrade