Manual

do

Maker

.

com

Socket UNIX invés de TCP/IP

Socket UNIX invés de TCP/IP

Para muitos, falar de domain socket unix é algo manjado, mas tão manjado que é como falar de mouse USB. Mas outros tantos não conhecem e é um recurso extremamente útil do sistema para fazer IPC (Inter-Process Communication). Esse recurso é muito utilizado e bastante útil tanto para sistemas grandes e complexos como para sistemas minimalistas rodando em embedded e por isso resolvi fazer o exemplo em cima do Raspberry, que roda um Linux tradicional tanto quanto roda Linux em uma arquitetura X86.

No primeiro momento pode ser difícil para você imaginar uma aplicação legítima para IPC, afinal é comum resolver tudo dentro de um mesmo programa, ou ainda, utilizar named pipe para esse propósito. Mas vamos a um exemplo bobo; um programa cria um arquivo com data/hora dentro, então repassa o nome do arquivo para o segundo processo, que lerá, exibirá na tela e então apagará o arquivo original. O server fica assim:

uds.py

# -*- coding: utf-8 -*-
#!/usr/bin/env python

import socket
import sys
import datetime
import os

tsLen = 10
#definicao do UDS
server_address = './uds_socket'

# Garanta primeiramente que o socket ja nao existe
try:
    os.unlink(server_address)
except OSError:
    if os.path.exists(server_address):
        raise
#Nesse ponto, sabe-se que nao existe o UDS. Cria-se:
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)

sock.bind(server_address)
#inicia a escuta
sock.listen(1)

#mantem-se interativo aa conexao
while True:
    connection, client_address = sock.accept()
    try:
        print >>sys.stderr, 'Origem:', client_address
        while True:
            data = connection.recv(tsLen)
            print >>sys.stderr,'Recebido: "%s"' % data
            if data:
                print >>sys.stderr,'Lendo conteudo...'
                filename =  str(data)+".txt"
                if os.path.isfile(filename):
                    f = open(filename,'r')
                    print >>sys.stderr, 'conteudo: ',f.readline()
                    f.close()
                    print >>sys.stderr,str(datetime.datetime.fromtimestamp(long(str(data))))
            else:
                print >>sys.stderr, 'Fim de processo', client_address
                break
    finally:
        connection.close()

Não confunda isso com gambiarra, porque não é. Apesar de estar sobre o sistema de arquivos, uds_socket (o nome dado a ele nesse programa, mas pode ser qualquer outro) é um arquivo descritor, executa-se em memória e não gera I/O em disco:

arquivo_descritor.webp

Um arquivo descritor aponta para um dispositivo, não é um arquivo comum no disco. Por exemplo, em /dev estão os dispositivos do sistema, como disco rígido, mouse, teclado, etc. Os dispositivos de armazenamento são chamados "dispositivos de bloco" e dispositivos como teclado e mouse são chamados "dispositivos de caractere". No caso do socket, ele é identificado pelo 's' de socket, como pode ser visto com o comando 'ls -l'. O tipo do arquivo pode ser visto com 'file uds_socket'. Tendo deixado isso claro, podemos partir para o client.

cli.py

# -*- coding: utf-8 -*-
#!/usr/bin/env python

import socket
import sys
import time

sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)

server_address = './uds_socket'
print >>sys.stderr, 'Conectando em %s' % server_address
try:
    sock.connect(server_address)
except:
    print >>sys.stderr, msg
    sys.exit(1)
    
try:
    ts = str(long(time.time()))
    f = open(ts+".txt","w")
    f.write(sys.argv[1]+"\n")
    f.close()
    sock.sendall(ts)
    
finally:
    print >>sys.stderr, 'Fechando conexao'
    sock.close()

Rode o server, então rode o cliente passando qualquer informação como parâmetro. Eu passei um "hello":

testing_socket.webp

Simples, hum?

Inscreva-se no nosso canal Manual do Maker no YouTube.

Também estamos no Instagram.

Nome do Autor

Djames Suhanko

Autor do blog "Do bit Ao Byte / Manual do Maker".

Viciado em embarcados desde 2006.
LinuxUser 158.760, desde 1997.