当线程化和服务器崩溃时,recv 命令无法正常工作
The recv command does not work as it should when threading and the server crashes
我使用 Python 套接字库设置了一个 TCP 服务器,可以连接多个设备。由于我在这里使用线程,所以我定期接受新的传入连接并尝试在列表中招募消息。我的问题是通常 recv 线程会卡在某个地方。有时运行顺利的服务器,有时第一天就挂了。显示传入连接但不接收消息。 c 在客户端中,所以当我在接收命令
之前打印每个线程连接时
Now on <socket.socket fd=8, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('172.31.15.96', 9680), raddr=('24.133.144.150', 56446)>
Now on <socket.socket fd=8, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('172.31.15.96', 9680), raddr=('24.133.144.150', 56446)>
Now on <socket.socket fd=8, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('172.31.15.96', 9680), raddr=('24.133.144.150', 56446)>
Now on <socket.socket fd=8, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('172.31.15.96', 9680), raddr=('24.133.144.150', 56446)>
Now on <socket.socket fd=8, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('172.31.15.96', 9680), raddr=('24.133.144.150', 56446)>
Now on <socket.socket fd=8, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('172.31.15.96', 9680), raddr=('24.133.144.150', 56446)>
Now on <socket.socket fd=8, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('172.31.15.96', 9680), raddr=('24.133.144.150', 56446)>
Now on <socket.socket fd=9, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('172.31.15.96', 9680), raddr=('24.133.144.150', 56456)>
在循环中,它继续显示同一个端口(可能超过一千次),直到它从 phone 发送了一条新消息。
我正在展示有问题的部分,因为我写的代码在 recv.
之后大约有 500 行
import socket
import threading
host = '172.31.15.96'
port = 9680
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print("socket created")
s.bind((host, port))
print("socket connected {} port".format(port))
s.listen(250)
print("socket listening")
db.logHere.insert_one({"socket log": {"socket created and port opened": port, "Time": time()}})
except socket.error as msg:
print("Error:", msg)
db.logHere.insert_one(
{"Socket Log": {"Error happened": msg, "Time": time()}})
clients = [] # this is list for connected client
def accept():
while True:
global clients
client, addr = s.accept()
print('Connection from:', addr)
db.logHere.insert_one({"Connection Log": {"Connection ip from": str(addr[0])+":"+str(addr[1]), "Connection time": time()}, "Time": time()})
clients.append(client)
def new_message():
while True:
for c in clients:
print("Now on", c) # I just try to use this print if new message thread work or stopped
try:
message = c.recv(2048)
if message:
#there is my split or sendall commands. I put if messages inside try advice from : Marquis of Lorne*
except socket.error as err:
print("socket error", err)
c.close()
threading.Thread(target=accept).start()
threading.Thread(target=new_message).start()
我应该怎么做才能解决这个问题并能够对每个传入连接正常运行,即保持服务器健康?
我认为我的主要问题是我无法删除客户端列表中断开连接的客户端。 try except 是不够的。我如何理解其中一个客户端断开连接?
**对于我不完整和不正确的语言用法,我深表歉意。我的母语不是英语。
这是对代码的最小修复,使用 select
仅读取具有可用数据的客户端套接字并从列表中删除已关闭的套接字:
...
def new_message():
while True:
# don't try to wait on a empty list...
if len(clients) == 0:
sleep(5)
else:
ready, _, _ = select.select(clients, [], [])
# only loop on sockets having available data to read
for c in ready:
print("Now on", c) # I just try to use this print if new message thread work or stopped
try:
message = c.recv(2048)
if message:
#there is my split or sendall commands. I put if messages inside try advice from : Marquis of Lorne*
print(message.decode())
else:
clients.remove(c)
except socket.error as err:
...
但实际上,您可以将侦听套接字包含在 select 列表中,并完全丢弃一个线程:
...
clients = [s] # this is list for connected client AND the listening socket
##def accept():
## while True:
## global clients
## client, addr = s.accept()
## print('Connection from:', addr)
## db.logHere.insert_one({"Connection Log": {"Connection ip from": str(addr[0])+":"+str(addr[1]), "Connection time": time()}, "Time": time()})
## clients.append(client)
def new_message():
while True:
ready, _, _ = select.select(clients, [], [])
for c in ready: # loop over ready sockets
if c == s: # special processing for listening one
try:
client, addr = s.accept()
except socket.error: # exit if the listening socket is closed
for x in clients:
x.close()
return
print('Connection from:', addr)
db.logHere.insert_one({"Connection Log": {"Connection ip from": str(addr[0])+":"+str(addr[1]), "Connection time": time()}, "Time": time()})
clients.append(client)
else:
print("Now on", c) # I just try to use this print if new message thread work or stopped
try:
message = c.recv(2048)
if message:
#there is my split or sendall commands. I put if messages inside try advice from : Marquis of Lorne*
print(message.decode())
else:
clients.remove(c)
except socket.error as err:
print("socket error", err)
c.close()
##threading.Thread(target=accept).start()
threading.Thread(target=new_message).start()
我使用 Python 套接字库设置了一个 TCP 服务器,可以连接多个设备。由于我在这里使用线程,所以我定期接受新的传入连接并尝试在列表中招募消息。我的问题是通常 recv 线程会卡在某个地方。有时运行顺利的服务器,有时第一天就挂了。显示传入连接但不接收消息。 c 在客户端中,所以当我在接收命令
之前打印每个线程连接时Now on <socket.socket fd=8, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('172.31.15.96', 9680), raddr=('24.133.144.150', 56446)>
Now on <socket.socket fd=8, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('172.31.15.96', 9680), raddr=('24.133.144.150', 56446)>
Now on <socket.socket fd=8, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('172.31.15.96', 9680), raddr=('24.133.144.150', 56446)>
Now on <socket.socket fd=8, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('172.31.15.96', 9680), raddr=('24.133.144.150', 56446)>
Now on <socket.socket fd=8, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('172.31.15.96', 9680), raddr=('24.133.144.150', 56446)>
Now on <socket.socket fd=8, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('172.31.15.96', 9680), raddr=('24.133.144.150', 56446)>
Now on <socket.socket fd=8, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('172.31.15.96', 9680), raddr=('24.133.144.150', 56446)>
Now on <socket.socket fd=9, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('172.31.15.96', 9680), raddr=('24.133.144.150', 56456)>
在循环中,它继续显示同一个端口(可能超过一千次),直到它从 phone 发送了一条新消息。 我正在展示有问题的部分,因为我写的代码在 recv.
之后大约有 500 行
import socket
import threading
host = '172.31.15.96'
port = 9680
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print("socket created")
s.bind((host, port))
print("socket connected {} port".format(port))
s.listen(250)
print("socket listening")
db.logHere.insert_one({"socket log": {"socket created and port opened": port, "Time": time()}})
except socket.error as msg:
print("Error:", msg)
db.logHere.insert_one(
{"Socket Log": {"Error happened": msg, "Time": time()}})
clients = [] # this is list for connected client
def accept():
while True:
global clients
client, addr = s.accept()
print('Connection from:', addr)
db.logHere.insert_one({"Connection Log": {"Connection ip from": str(addr[0])+":"+str(addr[1]), "Connection time": time()}, "Time": time()})
clients.append(client)
def new_message():
while True:
for c in clients:
print("Now on", c) # I just try to use this print if new message thread work or stopped
try:
message = c.recv(2048)
if message:
#there is my split or sendall commands. I put if messages inside try advice from : Marquis of Lorne*
except socket.error as err:
print("socket error", err)
c.close()
threading.Thread(target=accept).start()
threading.Thread(target=new_message).start()
我应该怎么做才能解决这个问题并能够对每个传入连接正常运行,即保持服务器健康? 我认为我的主要问题是我无法删除客户端列表中断开连接的客户端。 try except 是不够的。我如何理解其中一个客户端断开连接?
**对于我不完整和不正确的语言用法,我深表歉意。我的母语不是英语。
这是对代码的最小修复,使用 select
仅读取具有可用数据的客户端套接字并从列表中删除已关闭的套接字:
...
def new_message():
while True:
# don't try to wait on a empty list...
if len(clients) == 0:
sleep(5)
else:
ready, _, _ = select.select(clients, [], [])
# only loop on sockets having available data to read
for c in ready:
print("Now on", c) # I just try to use this print if new message thread work or stopped
try:
message = c.recv(2048)
if message:
#there is my split or sendall commands. I put if messages inside try advice from : Marquis of Lorne*
print(message.decode())
else:
clients.remove(c)
except socket.error as err:
...
但实际上,您可以将侦听套接字包含在 select 列表中,并完全丢弃一个线程:
...
clients = [s] # this is list for connected client AND the listening socket
##def accept():
## while True:
## global clients
## client, addr = s.accept()
## print('Connection from:', addr)
## db.logHere.insert_one({"Connection Log": {"Connection ip from": str(addr[0])+":"+str(addr[1]), "Connection time": time()}, "Time": time()})
## clients.append(client)
def new_message():
while True:
ready, _, _ = select.select(clients, [], [])
for c in ready: # loop over ready sockets
if c == s: # special processing for listening one
try:
client, addr = s.accept()
except socket.error: # exit if the listening socket is closed
for x in clients:
x.close()
return
print('Connection from:', addr)
db.logHere.insert_one({"Connection Log": {"Connection ip from": str(addr[0])+":"+str(addr[1]), "Connection time": time()}, "Time": time()})
clients.append(client)
else:
print("Now on", c) # I just try to use this print if new message thread work or stopped
try:
message = c.recv(2048)
if message:
#there is my split or sendall commands. I put if messages inside try advice from : Marquis of Lorne*
print(message.decode())
else:
clients.remove(c)
except socket.error as err:
print("socket error", err)
c.close()
##threading.Thread(target=accept).start()
threading.Thread(target=new_message).start()