python – Difficulty with socket.recv()

Question:

I'm having continuity problems in my code after a function call, related to receiving data via socket with the following code:

def le_dados(obj):

    lista_rcv = []
    while True:

        data = obj.recv(2)

        if data:
            lista_rcv.append(data)

            if len(lista_rcv) == 4:

                lista_rcv.append(obj.getpeername())
                global status_central
                status_central = lista_rcv
                lista_rcv = []

         sleep(0.25)

This function is called inside another function like this:

process = multiprocessing.Process(target=le_dados(s))
process.daemon = True    
process.start()

What I'm not able to see, maybe due to lack of experience, is because the code stops on the line:

data = obj.recv(2)

Not letting the code go forward in the process call, it is stopped here:

process = multiprocessing.Process(target=le_dados(s))

not letting me be my Bill that comes after that.

Just complementing, the rest of the code follows, it is used to connect to devices where I will send and receive commands, with just one it worked, but when I try with several I'm not getting it.

import socket
import os
import Gcomn
from time import sleep  
import multiprocessing

PORT = 7557

status_central = []
on_off_disp = []

def conecta_dispositivos():

    sql = 'select nome_disp, Ip_disp from dispositivos'
    dados_dis = Gcomn.le_dados(sql)
    global on_off_disp
    on_off_disp = []

    for i in range (len(dados_dis)):

        try:
            s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
            #s.settimeout(5)
            s.connect((dados_dis[i][1] ,7557))            

            if s:   
                print("Conectado a: ", s.getpeername())
                sleep (1.5)
                sendData()
                on_off_disp.append(1)

                print('vou chamar o process')
                process = multiprocessing.Process(target=recebe_dados(s))
                process.daemon = True
                process.start()
                print('depois do process')

        except socket.error:
            print ('Erro ao conectar em: ', dados_dis[i][0])
            on_off_disp.append(0)


def recebe_dados(obj):

    lista_rcv = []
    obj.setblocking(False)
    while True:
        data = obj.recv(2)
        if data:

            lista_rcv.append(data)

            if len(lista_rcv) == 4:
                lista_rcv.append(obj.getpeername())
                global status_central
                status_central = lista_rcv
                lista_rcv = []
        else:
            print('não recebi nada')        

        sleep(0.25)


def sendData(comando = 'A00000'):

    s.send(comando.encode('utf-8'))

conecta_dispositivos()

Answer:

As the connection will be made to several servers (devices) continuously, it will be necessary to create a socket for each one of the servers.

The recv function can be configured to work in modes: "lock" until receiving some data, unblock or block after a timeout .

The configuration you will use depends a lot on how you want the program to work (algorithm).

As your code uses multiprocessing, a possible strategy is to create a process for each client, moving all the looping code for i in range (len(dados_dis)): to a new process and leaving the connection configured as "block".

Each process will open a (different) connection with a device and handle the data independently.


Here, just as an example, your code modified with this change:

import socket
import os
import Gcomn
from time import sleep
import multiprocessing

PORT = 7557

status_central = []
on_off_disp = []

# Acrescentei o parâmetro: s (socket)
def sendData(s, comando = 'A00000'):
    s.send(comando.encode('utf-8'))

# Recebe os dados de 1 dispositivo no modo "bloqueio"
def recebe_dados(obj):
    lista_rcv = []
    while True:
        # Aqui, a conexão pode ser do tipo "bloqueio"
        data = obj.recv(2)
        if data:
            lista_rcv.append(data)
            if len(lista_rcv) == 4:
                lista_rcv.append(obj.getpeername())
                global status_central
                status_central = lista_rcv
                lista_rcv = []
        else:
            print('não recebi nada')
        sleep(0.25)

# Abre a conexão e mantém a comunicação com 1 dispositivo
def disp_interno(d):
    try:
        s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        s.connect((d[1] ,7557))
        if s:
            print("Conectado a: ", s.getpeername())
            sleep (1.5)
            sendData(s)
            on_off_disp.append(1)
            recebe_dados(s)
    except socket.error:
        print ('Erro ao conectar em: ', dados_dis[i][0])
        on_off_disp.append(0)

# Cria um processo diferente para cada dispositivo
def conecta_dispositivos():
    sql = 'select nome_disp, Ip_disp from dispositivos'
    dados_dis = Gcomn.le_dados(sql)
    global on_off_disp
    on_off_disp = []

    for i in range(len(dados_dis)):
        print('vou chamar o process')
        # Alterado para criar o processo, chamando a função: disp_interno
        # Envia como parâmetro os dados da conexão
        process = multiprocessing.Process(target=disp_interno, args=(dados_dis[i],))
        process.daemon = True
        process.start()
        print('depois do process')

    # o join() aguarda a finalização dos processos
    for process in multiprocessing.active_children():
        process.join()


if __name__=="__main__":
    conecta_dispositivos()

Comments:

  • As multiprocessing is used for communication with devices ( IO ), maybe there is an advantage in using Threads instead of Process .

  • The code inside the process(es) updates global variables ( status_central and on_off_disp ), so you may need to check whether or not there will berace condition problems.

  • If a problem occurs in one of the connections (the remote device closes the connection, network instability, etc.), the process responsible for this connection will "die" in the while True: looping while True: inside the recebe_dados() function. I believe this situation needs to be addressed as well.

Scroll to Top