简体   繁体   中英

BrokenPipeError: [Errno 32] Broken pipe for makefile socket?

I've made a socket where i need to stream some stdout data from a C file to my computer over ethernet. It works fine until i close the connection at client side where i then get the following error at the server socket:

    Traceback (most recent call last):
  File "/home/pi/Documents/av/network/server_socket.py", line 82, in <module>
    main()
  File "/home/pi/Documents/av/network/server_socket.py", line 67, in main
    sf.write(line.rstrip())
  File "/usr/lib/python3.9/socket.py", line 722, in write
    return self._sock.send(b)
BrokenPipeError: [Errno 32] Broken pipe

I would like the socket to go back to accept new connections when the client closes the connection. I've tried to read the python socket documentation but can't find anything about the issue. I could send a "quit" message to the server - but i would rather that the server just ignores the pipe is closed and goes back to accepting new connections.

I have my server code (i get the error on the server. I've outlined the issue by wrapping it in ## ISSUE IS HERE ##):

import socket
import time
import os
import subprocess

# start server and wait for connections
def startServerSocket(PORT):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
    sock.bind(('', PORT)) # bind loopback addr
    sock.listen(2)
    
    return sock

# initiate the ethernet protocol and log client to /var/log/pythonconnection.log
def readyConnection(conn, addr):
    # send request to get incoming connection host name        
    data = "whoisthis".encode()
    conn.sendall(data)

    # await with blocking recv for client response and log response
    data = conn.recv(1024)

    # need to be logged
    print("\nConnected to " , data.decode(), " as ", addr[0], " at [", time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())), "]")


    # tell that we're ready to start stream
    data = "ready".encode()
    conn.sendall(data)

    # get response saying client is ready to rec
    data = conn.recv(1024)
    if (data.decode()=="ready"):
        return True

    
    return False

        

def main():
    sock = startServerSocket(4000)
    print("waiting for connection... ")
  

    while True:
        conn, addr = sock.accept()

        # create serverfile to transmit IO signals to client via stream
        sf = conn.makefile("wrb", buffering=0)  
 
        # connection function
        connection = readyConnection(conn, addr)

        if (connection):
            print("[0/2] -> Valid connection established")
            print("[1/2] -> Printing stream to socket")
            
            # start reading from stdout in subprocess

            proc = subprocess.Popen(
                        ["/home/pi/Documents/av/sonar/a.out"],stdout=subprocess.PIPE)

            while True:
                line = proc.stdout.readline() # read one stdout line
                if not line:
                    break

                ## ISSUE IS HERE ##############
                sf.write(line.rstrip()) # write line to socket file
                ## ISSUE IS HERE ##############

                sf.flush() # force line to be sent immediately
            

        sf.close()
        conn.close()
        print("[x/x] -> Client has closed connection or stream reached EOF")
            






if __name__ == '__main__':
    main()

And my client code:

import socket
import time;

# function to setup and try to connect to a server
def connect(HOST, PORT):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)        
    sock.connect((HOST, PORT)) # raspberry pi addr + allowed port
    
    return sock


def handleRequest(data):
    output = ""
    if (data=="whoisthis"):
        output = socket.gethostname()
        print("-> Connecting as ", output)
    
    if (data=="ready"):
        print("-> Socket ready for IO")
        output = "ready" 
    
    return output
    


def main():

    sock = connect('123.123.1.69', 4000)
    cf = sock.makefile("wrb", buffering=0)

    while True:
        data = sock.recv(40).decode()
        handler = handleRequest(data)

        print(data.strip()+"\n")
        if (handler.strip() != ""):
            if (data.strip()=="ready"):
                sock.sendall("ready".encode()) # tell we're also ready to stream
                break ## exit loop
            
            sock.sendall(handler.encode())
        time.sleep(0.1) # just sleep while testing 

    # ready to recieve stream via ethernet
    print("-> ready to stream")
    while True:
        print(cf.read(64).decode()) # read 64 bytes at a time
        time.sleep(0.1)

if __name__ == '__main__':
    main()

Edit: I've also tried the select library for I/O based on https://docs.python.org/3/library/select.html where i just copied some code from https://stackoverflow.com/a/21802953/15386210

I solved the issue by just adding a try/except with BrokenPipeError to wrap the makefile write method. For anyone in the future here is the code that solved the brokepipe issue:

  proc = subprocess.Popen(
                    ["/home/pi/Documents/av/sonar/a.out"],stdout=subprocess.PIPE)

        while True:
            line = proc.stdout.readline() # read one stdout line
            if not line:
                break
            try:
                sf.write(line.rstrip()) # write line to socket file
            except (BrokenPipeError, IOError):
                print("an errror aka client disconnect")
                break
            sf.flush() # force line to be sent immediately
        

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