为什么Python客户端socket接收到回复但在某些线程中仍然抛出异常?
这是我的Python代码。它是一个“ping”客户端。它会向服务器发送一条消息,并期待在1秒内收到一个回复,回复的内容是把字母都变成大写。
from socket import *
import threading
import time
def ping_thread(num, clientSocket):
try:
clientSocket.settimeout(1)
t1 = time.perf_counter()
message = "Ping " + str(num) + " " + str(time.time())
clientSocket.sendto(message.encode(), (serverName, serverPort))
modifiedMessage, serverAddress = clientSocket.recvfrom(2048)
t2 = time.perf_counter()
lag = t2 - t1
print(f"{modifiedMessage.decode()}: {lag:.8f}s")
except TimeoutError:
print(f"ping {num} time out!")
if __name__ == "__main__":
threads = []
clientSocket = socket(AF_INET, SOCK_DGRAM)
serverName = "localhost"
serverPort = 12000
for i in range(1, 11):
t = threading.Thread(target=ping_thread, args=(i, clientSocket))
threads.append(t)
t.start()
for t in threads:
t.join()
clientSocket.close()
这是运行代码后的结果。
PING 2 1710845145.1677558: 0.00191080s
PING 5 1710845145.169752: 0.00126800sPING 6 1710845145.169752: 0.00098610s
PING 1 1710845145.1658478: 0.00588400s
PING 3 1710845145.1677558: 0.00067630s
PING 8 1710845145.1719148: 0.00477900s
PING 10 1710845145.172912: 0.00083350s
ping 10 time out!
ping 4 time out!
ping 2 time out!
我想知道为什么有些线程(比如上面的Ping 2)能收到回复,但仍然会抛出超时异常。非常感谢!
240320 这是服务器的代码。它来自于《计算机网络:自顶向下的方法》的实验2。
# We will need the following module to generate randomized lost packets
import random
from socket import *
# Create a UDP socket
# Notice the use of SOCK_DGRAM for UDP packets
serverSocket = socket(AF_INET, SOCK_DGRAM)
# Assign IP address and port number to socket
serverSocket.bind(('', 12000))
while True:
# Generate random number in the range of 0 to 10
rand = random.randint(0, 10)
# Receive the client packet along with the address it is coming from
message, address = serverSocket.recvfrom(1024)
# Capitalize the message from the client
message = message.upper()
# If rand is less than 4, we consider the packet lost and do not respond
if rand < 4:
continue
# Otherwise, the server responds
serverSocket.sendto(message, address)
1 个回答
1
你的服务器代码似乎随机忽略了大约40%的消息。因为所有10条消息都是通过同一个连接(socket)发送的,所以大约6条返回的消息可能会被任何一个线程处理。
如果你在服务器代码中加上一条打印语句:
if rand < 4:
print('ignored', message)
continue
你会发现大约有4条消息被忽略了,但大约6个线程会收到这些响应,而且顺序是混乱的。这样大约有4个线程会因为没有收到消息而超时。
为了确保正确的线程能收到正确的响应,建议为每个线程使用一个单独的连接:
def ping_thread(num): # don't pass common socket
try:
clientSocket = socket(AF_INET, SOCK_DGRAM) # unique socket for thread
clientSocket.settimeout(1)
t1 = time.perf_counter()
message = "Ping " + str(num) + " " + str(time.time())
clientSocket.sendto(message.encode(), (serverName, serverPort))
modifiedMessage, serverAddress = clientSocket.recvfrom(2048)
t2 = time.perf_counter()
lag = t2 - t1
print(f"{modifiedMessage.decode()}: {lag:.8f}s")
except TimeoutError:
print(f"ping {num} time out!")
with socket(AF_INET, SOCK_DGRAM) as clientSocket:
serverName = "localhost"
serverPort = 12000
# Create threads passing only the thread number.
threads = [threading.Thread(target=ping_thread, args=(i,)) for i in range(10)]
for t in threads:
t.start()
for t in threads:
t.join()
输出结果。在这种情况下,有3条响应被忽略(2,3,8),而这些就是超时的消息。
ignored b'PING 3 1710957710.7031364'
PING 0 1710957710.7031364: 0.00558820s
PING 6 1710957710.7031364: 0.00411860s
PING 4 1710957710.7031364: 0.00456480s
PING 1 1710957710.7031364: 0.00579830s
PING 5 1710957710.7031364: 0.00471390s
ignored b'PING 8 1710957710.7031364'
PING 7 1710957710.7031364: 0.00405850s
ignored b'PING 2 1710957710.7031364'
PING 9 1710957710.7031364: 0.00469280s
ping 3 time out!
ping 8 time out!
ping 2 time out!