Que es un socket?

Seguramente encontrará variadas definiciones de lo que es un Socket en redes informáticas, sin embargo desde el punto de vista de la electrónica con microcontroladores, podríamos simplemente decir que es el RS-232 de TCP-IP.

Una de las formas mas simples de conectar un microcontrolador, PLC o electrónica en general a una computadora es a través de una UART con el conocido protocolo RS-232. Un socket hace eso mismo, establece una conexión entre dos puntos, sin importar donde se encuentren estos puntos y esto si es una gran diferencia con el viejo RS-232.

Podemos hacer una medición de voltaje, temperatura, humedad o lo que fuera necesario verificar y transmitir estos datos a cualquier parte del mundo por TCP-IP para esto solo necesitamos tres cosas:

  1. Una dirección IP donde enviar los datos.
  2. Un puerto virtual donde los datos será recogidos.
  3. El conocimiento para darle forma a la idea wink

Un poco de teoría.

Hay varios tipos de socket pero dos son de uso mas común.

  • Los socket de flujoSOCK_STREAM que son transportados por TCP (Protocolo de Control de Transmisión) y asegura que los mensajes lleguen en el mismo  orden que fueron enviados y sin errores. Telnet, los navegadores y muchas aplicaciones usan este tipo de conexión fiable y segura.
  • Los socket de datagramaSOCK_DGRAM son transportados por UDP (Protocolo de Datagramas de Usuario), Es la forma mas simple de enviar datos por la red. Simplemente montamos un paquete le damos una dirección destino y un puerto y listo!! El SOCK_DGRAM es mas rápido que el anterior pero claro aquí no importa el orden en que los paquetes llegan y varias cosas mas no son tomadas en cuenta motivo por el cual es mas rápido. Pero cuando lo que enviamos son simples datos de una medición o el estado de una máquina y solo estaremos usando la conexión para enviar datos sueltos y esporádicos (mismo que hacemos con RS-232 y microcontroladores) este tipo de socket es ideal para mover datos con nuestra electrónica.

El socket servidor.

Esta forma de comunicarnos es cliente-servidor. En el ejemplo que vemos estamos haciendo una medición de voltaje con un conversor A/D, esta medición la montamos en un paquete y lo enviamos a una dirección y puerto en la red.

El programa usado es Python corriendo en GNU-Linux Debian (pero podemos ejecutar el script en cualquier sistema que tenga el interprete Python).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# -*- coding: utf-8 -*-
#!/usr/bin/env python
import socket
from Tkinter import *
from tkMessageBox import showinfo
 
class MyGui(Frame):
    def __init__(self, parent=None):
        Frame.__init__(self, parent)
 
UDP_IP ="201.187.1.168" # ip del socket
UDP_PORT = 6000  # Puerto del socket
 
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
sock.bind((UDP_IP, UDP_PORT))
 
x = 0
y = 0

def update_label():
    data, addr = sock.recvfrom(1024) 
    label.config(text = data)
    label.after(100, update_label)

 
def info():
        showinfo(title='Acerca de..', message='Script en Python \n www.firtec.com.ar')
 
 
def makemenu(parent):
    menubar = Frame(parent)
    menubar.pack(side=TOP, fill=X)
 
    fbutton = Menubutton(menubar, text='Menu', underline=0)
    fbutton.pack(side=LEFT)
    file = Menu(fbutton)
    file.add_command(label='Acerca de...', command=info,     underline=0)
    file.add_command(label='Salir',    command=parent.quit, underline=0)
    fbutton.config(menu=file)
 
ventana = Tk()
 
ventana.title('Socket en Python')
ventana.config(bg="beige") 
ventana.geometry("400x200") 
 
ventana.resizable(0,0) 
 
makemenu(ventana)
 
label = Label(ventana, text="Voltios:???", bg="beige", fg="red", font=("Helvetica", 28))
label.place(x=100, y=80)
 
label.after(100, update_label)
ventana.mainloop( )

En estas líneas el socket es creado:

UDP_IP ="201.187.1.168" # ip del socket
UDP_PORT = 6000         # Puerto del socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) <<<<
Socket UDP
sock.bind((UDP_IP, UDP_PORT))

Los datos son recibidos en data:

data, addr = sock.recvfrom(1024) 


El resultado final.

Para poder recibir los datos en Linux deberemos solicitar permisos en el firewall.

 El socket cliente.

Del lado de la electrónica y para simplificar las cosas estamos usando una placa Raspberry con un conversor analógico SPI de Microchip y el código completo del cliente es el siguiente.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# www.firtec.com.ar - Esta dirección de correo electrónico está siendo protegida contra los robots de spam. Necesita tener JavaScript habilitado para poder verlo.
# -*- coding: utf-8 -*-
import RPi.GPIO as GPIO
import time
import spidev
import socket
 
GPIO.setmode(GPIO.BCM)
spi = spidev.SpiDev()
spi.open(0, 0)
UDP_IP ="202.108.1.110" # ip del cliente
 
UDP_PORT = 6000
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP
 
while True:
    try:
        adc = spi.xfer2([0, 0])
        hi = (adc[0] & 0x1F);
        low = (adc[1] & 0xFe);
        dato = (hi << 8) | low;
        Va = (long) (dato) * 3.3 / 8192.0;
        sock.sendto("Voltios:% .2f" % Va, (UDP_IP, UDP_PORT))
        time.sleep(0.5)
 
    except (KeyboardInterrupt, SystemExit):
        spi.close()
        raise

 

La implementación de Socket es muy útil y práctico incluso para mover datos dentro de una red interna pudiendo usar los propios sistemas WiFi de los equipos involucrados, también podemos trabajar con distintos puertos para diferentes datos. (Algo así como canales distintos para diferentes datos en una misma dirección).

En una conexión Ethernet por ejemplo con un controlador mas modesto que una Raspberry podríamos mover datos en la red por UDP de la misma forma que en otro tiempo usábamos RS-232 en los microcontroladores de 8 bits pero a una velocidad mucho mayor y sin límites de distancias.

Información extraída de nuestro libro Electrónica con MicroPython.