我正在编写客户端 - 服务器即时消息程序。我在Python 2中创建了一个类似的程序,我正在尝试用Python 3编程。问题是当服务器接收消息并尝试将其发送到另一个客户端时,它给了我“[Errno 32] Broken Pipe”和退出。
我做了一些研究,发现当客户端断开连接时会发生这种情况,所以我做了一些测试,但是在客户端断开连接时无法找到。 (我使用的是Ubuntu 14.04和Python 3.4)
这是服务器代码:
unsigned
客户端代码:
import socket, select, sys
def broadcast(sock, messaged):
for socket in connection_list:
if socket != s and socket != sock:
# Here is where it gives me the broken pipe error
try:
s.send(messaged.encode("utf-8"))
except BrokenPipeError as e:
print(e)
sys.exit()
connection_list = []
host = ''
port = 5558
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((host,port))
s.listen(5)
connection_list.append(s)
read_sockets,write_sockets,error_sockets = select.select(connection_list,[],[])
while True:
for sock in read_sockets:
if sock == s:
conn, addr = s.accept()
connection_list.append(conn)
client = "Client (%s,%s) connected" % addr
print(client)
broadcast(sock,client)
else:
try:
data = sock.recv(2048)
decodeddata = data.decode("utf-8")
if data:
broadcast(sock, decodeddata)
except:
offline = "Client " + addr + "is offline"
broadcast(sock, offline)
print(offline)
connection_list.remove(sock)
sock.close()
continue
答案 0 :(得分:1)
要完成这项工作,您必须解决两个问题。
首先,在客户端和服务器端,你必须将CordovaWebView
放在循环中,而不是在外面。否则,如果在你进入循环之前有什么需要阅读的话,你会一遍又一遍地回忆,如果没有,你就永远不会回忆。解决这个问题后,您可以摆脱select
。 (你应该从不需要一个time.sleep(1)
来解决这样的问题;充其量它会掩盖问题,并且通常会引入新问题。)
同时,在服务器端sleep
内,您正在执行broadcast
。但s.send
是您的侦听器套接字,而不是连接的客户端套接字。您需要s
,因为socket.send
是socket
中的每个套接字。
您的代码中也存在许多无关的问题。例如:
connection_list
是假设要捕获的内容。它主要似乎捕获的是,大约50%的时间,命中^ C结束程序会触发发送提示。但是,当然,就像任何裸except:
一样,它也会掩盖代码中的任何其他问题。except:
子句之外的消息。except:
是主机和端口的元组,因此当有人离线时,服务器会因尝试格式化离线消息而引发addr
。TypeError
始终是最后连接的客户,而不是断开连接的客户。addr
上查看EOF。这意味着在您收到错误之前,您实际上并未检测到客户端已脱机。这通常只有在您尝试recv
他们发送消息后才会发生(例如,因为其他人已连接或断开连接)。