Difficulty with socket.recv()

Asked

Viewed 529 times

3

I am experiencing continuity issues 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 within another function like this:

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

What I’m failing to visualize, perhaps from lack of experience, is why the code stops on the line:

data = obj.recv(2)

Not letting the code go ahead on the call of process, stands here:

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

not leaving so I amaze my Gui that comes after that.

Only complementing, follow the rest of the code, it is used to connect to devices where I will send and receive commands, with only one worked, but when I try with several I am not getting.

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()
  • Probably the call recv is blocking the execution until it receives some data through the socket. You can set the connection not to lock the program as soon as you create the socket obj with obj.setblocking(False), however, you will need to address the case where you called the recv and received no data

  • Thanks for the answer, by doing this, the program jumps and executes the rest, however, the block that is called in the process that is le_dados(), does not work.

  • If you change the socket not to block, you will also need to change your algorithm. With the code that is in the question ("locking"), you tried to connect to socket from another program (eg telnet) and send some data? It has not unlocked?

  • I’m trying to connect with some devices that work in server mode, I made a code that works with one and sends and receives commands normally but when I try to connect with several appears the problem. I made a loop for and got a list from the bank with the registered devices and try to connect with each one. Maybe that’s the problem. don’t know how to put all the code in the same question. just editing?

  • Yes. Just edit the question and add all that information and code! :)

1 answer

1

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

The function recv can be set to work in modes: "lock" until you receive some data, do not lock or lock after a timeout.

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

Because your code uses multiprocessing, one possible strategy is to create a process for each client by moving the entire code of the looping for i in range (len(dados_dis)): for a new process and let the connection set to "block".

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


Just for example, follow your modified code 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()


Remarks:

  • How multiprocessing is used for communication with devices (IO), maybe there’s an advantage to using Threads instead of Process.

  • Code within process(s) updates global variables (status_central and on_off_disp), therefore, it may be necessary to check whether or not there will be problems of race condition.

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

  • Gomiero, thank you so much for the answer was of great value, researching a little, I started to use threads even as you advised, and much is already working, and, I am aware that there is still a more accurate treatment in this module that is where I am working now.

  • @Rafa710: You’re welcome! :)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.