简体   繁体   中英

Sending and receiving using sockets python

I am trying to create a function to send and receive information over a socket client & server. It appears that my code is somehow blocking. In the code the first command iteration in my for loop is carried out but then the process becomes blocked. Does anyone have any suggestions how to do this using threading or multithreading?

My code is below:

import socket
import json
import sys
import time
import select
import queue

Ni_Rio_IP= "172.22.11.2"
Ni_Base_IP= "172.22.11.1"

class AliceRio:

    def __init__(self, ip_rio, ip_pc):
        self.ip_rio = ip_rio
        AliceRio.udp_port_rio = 60006
        self.ip_pc = ip_pc
        AliceRio.udp_port_pc = 50005
        AliceRio.json= '{"Dest":"","Name":"","Time":"","Val":{"Str":[],"Pos":[[]],"Data":[[]]},"IP":0,"Port":0,"RT error":{"status":false,"code":0,"source":""}}'
        AliceRio.dict= json.loads(self.json)
    
    def PrintUDP(self):
        print("RIO IP: %s" % self.ip_rio)
        print("RIO UDP port: %s" % self.udp_port_rio)
        print("PC IP: %s" % self.ip_pc)
        print("PC UDP port: %s" % self.udp_port_pc)

    def SendRec(self, send_str):
        # Set up socket for sending
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # Internet, UDP
        sock.sendto(bytes(send_str, 'utf-8'), (self.ip_rio, self.udp_port_rio))
        sock.close()
        print('got here')
        # Set up socket for receiving
        sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # Internet, UDP
        sock.bind((self.ip_pc, self.udp_port_pc))   
        rec_str, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
        print('got here2')
        sock.close()
        return rec_str
        
    def Receive(self, rec_str):
        sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # Internet, UDP
        sock.bind((self.ip_pc, self.udp_port_pc))   
        rec_str, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
        sock.close()
        return rec_str
        
    def Send(self, send_str):
        # Set up socket for sending
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # Internet, UDP
        sock.sendto(bytes(send_str, 'utf-8'), (self.ip_rio, self.udp_port_rio))
        sock.close()
        #return rec_str
    
    def Aim(self, aim_perc):
        if aim_perc < 0 or aim_perc > 100: return "aim_perc out of range"
        send_dict=AliceRio.dict
        send_dict["Dest"]='Rio'
        send_dict["Name"]='Laser Control'
        Laser_Mode=1
        Simmer_A=0
        Pulse_A= 0
        Pulse_ms= 20
        
        send_dict["Val"]["Str"]=[str(Laser_Mode), str(aim_perc), str(Simmer_A), str(Pulse_A), str(Pulse_ms)]
        send_json=json.dumps(send_dict)
        
        # send it out
        self.SendRec(send_json)
        rec_json= self.SendRec(send_json)
        rec_dict=json.loads(rec_json)
        
        return "Aim laser now at " + rec_dict["Val"]["Str"][1] +'%' 

    def PWM_Laser_Fan(self, fan_perc):
        send_dict=AliceRio.dict
        send_dict["Dest"]='Rio'
        send_dict["Name"]='PWM Laser'       
        send_dict["Val"]["Str"][0]=str(fan_perc)
        send_json=json.dumps(send_dict)
     
        # send it out
        rec_json= self.SendRec(send_json)
        rec_dict=json.loads(rec_json)
        return rec_dict["Val"]["Str"][0]

    def Poll(self):
        send_dict=AliceRio.dict
        send_dict["Dest"]='Rio'
        send_dict["Name"]='Poll'       
        send_json=json.dumps(send_dict)
        # send it out
        rec_json= self.SendRec(send_json)
        rec_dict=json.loads(rec_json)
        
        if rec_dict["Val"]["Data"][0][0]==0: pid_mode='off' 
        else: pid_mode='PID' 
        print('PID mode:', pid_mode)
        print('Pos X:', rec_dict["Val"]["Data"][0][1])
        print('Pos Y:', rec_dict["Val"]["Data"][0][2])
        print('Home:', rec_dict["Val"]["Data"][0][3])
        print('Enabled:', rec_dict["Val"]["Data"][0][4])
    
    def PIDControl(self, pid_mode,pid_center):
        if pid_mode=="off": mode= 0
        elif pid_mode=="PID":mode =1
        else: return "pid_mode not valid"
        
        if pid_center[0] not in range(-2048,2048): return "center x-pos not in range"
        if pid_center[1] not in range(-2048,2048): return "center y-pos not in range"
    
        send_dict=AliceRio.dict
        send_dict["Dest"]='Rio'
        send_dict["Name"]='PID Control'
        send_dict["Val"]["Str"]=[str(mode), str(pid_center[0]), str(pid_center[1])]
        send_json=json.dumps(send_dict)
        # send it out
        rec_json= self.SendRec(send_json)
        rec_dict=json.loads(rec_json)
        return "PID mode now at " + rec_dict["Val"]["Str"][0]
           

Alice1 = AliceRio(Ni_Rio_IP, Ni_Base_IP)
Alice1.PrintUDP()

for i in range(10):
    Alice1.Aim((i*10)+10)
    time.sleep(0.2)

I would suggest learning to use Pdb and trace through the execution of your program to find where it is getting caught.

Also when learning/developing with sockets I've found that it helps to have separate programs for your client and server in the beginning so you can see how both sides are handling exchanges instead of going the threading route to start since the logging can get confusing, best of luck!

Module threading does help in this scenario. We can create a thread to receiving incoming messages. And when new message received the thread trigger an event to notify the waiting method SendRec .

import sys
import socket
import json
import threading
import time


class AliceRio:

    def __init__(self, .....):
        
        # .........
        
        self.s_in = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.s_in.bind((self.ip_pc, self.udp_port_pc))
        self.evt = threading.Event()
        self.last_msg = None

    def _recv(self):
        while True:
            msg, _ = self.s_in.recvfrom(1024)
            self.last_msg = msg
            self.evt.set()

    def SendRec(self, send_str):
        if not hasattr(self, 'th_recv'):
            th = threading.Thread(target=self._recv)
            th.setDaemon(True)
            th.start()
            self.th_recv = th

        self.evt.clear()

        rio_endpoint = (self.ip_rio, self.udp_port_rio)
        s_out = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s_out.sendto(bytes(send_str, 'utf-8'), rio_endpoint)
        s_out.close()
        if self.evt.wait(timeout=15.0) and self.last_msg:
            return self.last_msg
        raise Exception('timeout waiting for response.')

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM