BrokenPipeError:[Erno 32]makefile套接字的管道破裂



我制作了一个套接字,需要通过以太网将一些stdout数据从C文件流式传输到我的计算机。它运行良好,直到我关闭客户端的连接,然后在服务器套接字上出现以下错误:

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

我希望套接字在客户端关闭连接时返回以接受新的连接。我试着阅读了python套接字文档,但找不到任何关于这个问题的信息。我可以发送一个";退出";消息发送给服务器,但我宁愿服务器忽略管道已关闭并返回接受新连接。

我有我的服务器代码(我在服务器上得到了错误。我已经通过将其包装在##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()

我的客户代码:

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()

编辑:我还尝试了基于的I/O选择库https://docs.python.org/3/library/select.html我刚从那里复制了一些代码https://stackoverflow.com/a/21802953/15386210

我只添加了一个带有BrokenPipeError的try/except来包装makefile写入方法,就解决了这个问题。对于未来的任何人来说,以下是解决brokpipe问题的代码:

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

最新更新