7

I am trying to send instructions from a Django website to a robot(Raspberry Pi) using Sockets but whenever I try and send a second instruction from the website it gives me the error. If you have any idea what is causing this, the help would be amazing! Website Send View:

def form_valid(self, form, **kwargs):
        robo_pk = self.kwargs['pk']
        robo = Robot.objects.get(pk=robo_pk)
        PORT = robo.port
        SERVER = robo.server
        ADDR = (SERVER, PORT)
        self.object = form.save()
        client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        client.connect(ADDR)

        def send(msg):
            message = msg.encode(FORMAT)
            msg_length = len(message)
            send_length = str(msg_length).encode(FORMAT)
            send_length += b' ' * (HEADER - len(send_length))
            client.send(send_length)
            client.send(message)

        send(form.cleaned_data['path_options'])
        send("MESSAGE SENT :) !")
        send(DISCONNECT_MESSAGE)
        return render(self.request, "dashboard-home/thank-you.html")

ERROR TRACEBACK:

Traceback (most recent call last):
  File "/usr/lib/python3.7/threading.py", line 917, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.7/threading.py", line 865, in run
    self._target(*self._args, **self._kwargs)
  File "main.py", line 46, in handle_client
    conn.send("MSG Received".encode(FORMAT))
BrokenPipeError: [Errno 32] Broken pipe

Relevant Code:

def handle_client(conn, addr):
    print(f"[NEW CONNECTION] {addr} connected")
    connected = True
    while connected:
        msg_length = conn.recv(HEADER).decode(FORMAT)
        if msg_length:
            msg_length = int(msg_length)
            msg = conn.recv(msg_length).decode(FORMAT)
            if msg == '!DISCONNECT!':
                connected = False
                print("disconnect")
                break
            else:
                my_queue.put(msg)
            print(f"[{ADDR}] {msg}")
            conn.send("MSG Received".encode(FORMAT))
    conn.close()
def start():
    server.listen()
    print(f"[LISTENING] Server Is Listening On {SERVER}")
    while True:
        print("before")
        conn,addr = server.accept()
        print("after")
        thread = threading.Thread(target=handle_client, args=(conn, addr))
        thread.start()
        print(f"[ACTIVE CONNECTIONS] {threading.activeCount()}")

print("[Starting] Server")
threading.Thread(target=start).start()

msg = my_queue.get()
Garberchov
  • 67
  • 1
  • 15
  • 1
    Did you check if Raberry Pi closed socket before receiving all data? This link may help you: https://stackoverflow.com/questions/11866792/how-to-prevent-errno-32-broken-pipe – Reza Akraminejad Dec 09 '21 at 20:00
  • @Hamed_gibago I see the question, but I am not fully sure how it relates or what the solution is here? Can you explain? – Garberchov Dec 10 '21 at 15:32
  • I think you've better open a socket for test and see when socket will close from website. Another solution is, first receive all data from website, and if it not large, just save it into your variable (ram) and after receiving all data, close socket and then send it to your resberry Pi. – Reza Akraminejad Dec 10 '21 at 15:47

2 Answers2

1

You are disconnecting the client before receiving all messages. To demonstrate this, run again with conn.close commented out. You're missing additional logic to ensure all pending requests have been processed before closing the connection.

References

https://stackoverflow.com/a/11866962/806876

pygeek
  • 7,356
  • 1
  • 20
  • 41
0

The django client is disconnecting immediately after sending DISCONNECT_MESSAGE. The server detects the connection close and invalidates the conn socket, causing the exception. This invalidation can happen, for example, between the recv() for the message "MESSAGE SENT :)" and the server's response (conn.send()) to this.

See How to handle a broken pipe (SIGPIPE) in python? for further info.

NeroP
  • 11
  • 1