python3-使用socket.send()时发生断管错误
我正在编写一个客户机-服务器即时消息程序。我在Python2中创建了一个类似的程序,并尝试在Python3中编程。问题是,当服务器接收消息并尝试将其发送到另一个客户端时,它会给我“[Errno 32]断管”并退出 我做了一些研究,发现当客户端断开连接时会发生这种情况,所以我做了更多的测试,但没有找到客户端断开连接的时间。(我正在使用Ubuntu 14.04和Python 3.4) 以下是服务器代码:python3-使用socket.send()时发生断管错误,python,sockets,python-3.x,Python,Sockets,Python 3.x,我正在编写一个客户机-服务器即时消息程序。我在Python2中创建了一个类似的程序,并尝试在Python3中编程。问题是,当服务器接收消息并尝试将其发送到另一个客户端时,它会给我“[Errno 32]断管”并退出 我做了一些研究,发现当客户端断开连接时会发生这种情况,所以我做了更多的测试,但没有找到客户端断开连接的时间。(我正在使用Ubuntu 14.04和Python 3.4) 以下是服务器代码: import socket, select, sys def broadcast(sock,
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
和客户端代码:
import socket, select, string, sys, time
def prompt(data) :
print("<You> " + data)
def Person(data) :
print("<Receiver> " + data)
if __name__ == "__main__":
host = "localhost"
port = 5558
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(2)
try:
s.connect((host,port))
except:
print('Unable to connect')
sys.exit()
print('Connected.')
socket_list = [s]
read_sockets,write_sockets,error_sockets = select.select(socket_list,[],[])
while 1:
for sock in read_sockets:
if sock == s:
try:
time.sleep(1)
data = sock.recv(1024)
Person(data.decode("utf-8"))
except:
msg = input("Send a message: ")
try:
s.send(str.encode(msg))
except:
print("Server is offline")
sys.exit()
else:
print("Server is offline")
sys.exit()
导入套接字、选择、字符串、系统、时间
def提示符(数据):
打印(“+”数据)
def人员(数据):
打印(“+”数据)
如果名称=“\uuuuu main\uuuuuuuu”:
host=“localhost”
端口=5558
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s、 设置超时(2)
尝试:
s、 连接((主机、端口))
除:
打印('无法连接')
sys.exit()
打印('已连接')
套接字\u列表=[s]
读插槽,写插槽,错误插槽=选择。选择(插槽列表,[],[])
而1:
对于插入式读_插槽:
如果sock==s:
尝试:
时间。睡眠(1)
数据=sock.recv(1024)
人员(数据解码(“utf-8”))
除:
msg=输入(“发送消息:”)
尝试:
s、 发送(str.encode(msg))
除:
打印(“服务器脱机”)
sys.exit()
其他:
打印(“服务器脱机”)
sys.exit()
要使其正常工作,您必须解决两个问题
首先,在客户端和服务器端,必须将select
放在循环内部,而不是外部。否则,如果在你进入循环之前有一些东西要读,你会一遍又一遍地记录,如果没有,你永远不会记录。一旦你解决了这个问题,你就可以摆脱时间。睡眠(1)。(解决这样的问题永远不需要睡眠
;它最多只能掩盖问题,通常会引入新问题。)
同时,在服务器端,在广播
内部,您正在执行s.send
。但是s
是您的侦听器套接字,而不是连接的客户端套接字。您需要socket.send
,因为socket
是connection\u列表中的每个套接字
代码中也有许多不相关的问题。例如:
- 我不确定客户端中的
应该捕获什么,除了:
。它似乎主要捕捉到的是,大约50%的时间,点击^C结束程序会触发发送提示。但是,当然,与除了:
之外的任何裸一样,它也掩盖了代码中的任何其他问题
除了“connected”消息之外,没有其他方法来回发送任何数据,除了except:
子句
addr
是主机和端口的元组,因此当有人脱机时,服务器会因试图格式化脱机消息而引发TypeError
addr
始终是最后一个连接的客户端,而不是断开连接的客户端
您没有将套接字设置为非阻塞模式
您没有在recv
上检查EOF。这意味着您在收到错误之前不会真正检测到客户端已脱机。通常只有在您尝试向他们发送消息后才会发生这种情况(例如,因为其他人已连接或断开连接)
您正在实施应用程序吗?供将来参考:您需要在普通文本和缩进代码之间留一个空行,或者代码的格式不是代码。我为您解决了这个问题。一个明显的问题是,您没有在循环中调用select
,您只调用了一次,然后假设由于套接字只可读一次,所以它将永远可读。通常,使用bareexcept:
子句会使代码很难调试,因为你看不到实际的异常发生。例如,当您进入服务器中的“脱机”代码时,并不总是因为客户端断开了连接,而是因为您忽略了实际的异常,所以无法判断。