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