如何使用 UDP python 套接字从服务器向客户端发送大图像 (2MB) 多个文件
How to send big image (2MB) multiple files from server to client with UDP python socket
我想通过 UDP 传输多张图片。我知道可以使用 TCP,但我希望它通过 UDP。下面是我使用的代码片段。是否可以通过 UDP 传输更大的文件?我设法传输小文件,但无法传输大文件。我感谢使用 UDP 套接字的任何帮助或替代方法。
接收图片的客户端代码。
BUF_SIZE = 1024
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('localhost', port))
sock.settimeout(30)
def rcv_data(sock, num_packet_to_recv, file_size):
bytes_rcvd = bytearray()
f = open(download_dir , 'wb')
print('Receiving packets will start')
while num_packet_to_recv > 0:
try:
client_data, server_addr = sock.recvfrom(BUF_SIZE + 8)
seq_num = client_b_data[-8:]
img_data = client_data[:-8]
num_packet_to_recv = num_packet_to_recv - 1
#store img_data and seq_num to bytes_rcvd for later
#sorting by sequence number
f.write(sorted_bytes_rcvd)
except Exception as e:
print('rcv error {}'.format(e))
f.close()
服务器端发送数据
def send_img(host, port, file_name, num_pkt):
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setblocking(0)
sock.settimeout(60)
client_addr = (host, port)
# send the file name
while num_pkt > 0:
img_part = requested_file.read(BUF_SIZE + 8)
sock.sendto(img_part + seq_num)
num_pkt -= 1
您发布的代码似乎假设在从发送方到接收方的途中不会丢弃任何数据包——这个假设在现实生活中不成立(甚至不成立)当发送方和接收方都位于同一台机器上时!),这是您的传输无法正常工作的最可能原因,除非是非常小的文件(您可以依靠运气来确保所有数据包都成功通过第一次尝试)。
为了实现更健壮的机制,您的接收程序将需要一些方法来 (a) 检测数据包何时被丢弃,以及 (b) 通过将消息发送回请求发送方的发送方来对这些知识做出反应重新传输 "lost" 数据包中的数据。 (当然,重传请求数据包也可能被丢弃,因此您也需要一种方法来处理它!)
与此同时,您的发送程序不仅需要发送数据(就像它目前所做的那样),还需要从接收方接收任何传入的重传请求数据包,并通过重传请求的数据来对它们做出反应。
根据协议的具体设计,发送方和接收方可能还需要在经过一定时间后没有发送或接收数据后采取行动,以避免文件传输过程在以下情况下停滞所有接收会提前的数据包都被丢弃。
因此,您当前仅在循环中调用阻塞 sendto()
或 recvfrom()
的方法是不够的;相反,发送方和接收方都需要实现某种状态机,使它们既可以在适当的时间发送适当的数据包,又可以快速接收和处理传入的任何数据包。这通常可以通过单独的方式完成发送者和接收者线程,或者通过将套接字设置为非阻塞模式并围绕对 select()
或 poll()
的阻塞调用编写事件循环。 (我更喜欢后者,因为在我看来,虽然状态机很难做到正确,但多线程更棘手)
将序列号放入每个数据包是一个好的开始;这允许接收方知道如何对数据进行排序,并允许它检测接收到的数据中何时存在 "hole"。一旦它检测到一个漏洞(即一个或多个丢失的序列号),它可以将一个数据包发送回发送方,要求重新发送这些数据包,并且由发送方通过重新发送这些数据包来做出反应.根据需要重复,直到接收方收到一个包含所有可能序列号的数据包(您还需要以某种方式与接收方通信期望有多少序列号)。
我想通过 UDP 传输多张图片。我知道可以使用 TCP,但我希望它通过 UDP。下面是我使用的代码片段。是否可以通过 UDP 传输更大的文件?我设法传输小文件,但无法传输大文件。我感谢使用 UDP 套接字的任何帮助或替代方法。
接收图片的客户端代码。
BUF_SIZE = 1024
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('localhost', port))
sock.settimeout(30)
def rcv_data(sock, num_packet_to_recv, file_size):
bytes_rcvd = bytearray()
f = open(download_dir , 'wb')
print('Receiving packets will start')
while num_packet_to_recv > 0:
try:
client_data, server_addr = sock.recvfrom(BUF_SIZE + 8)
seq_num = client_b_data[-8:]
img_data = client_data[:-8]
num_packet_to_recv = num_packet_to_recv - 1
#store img_data and seq_num to bytes_rcvd for later
#sorting by sequence number
f.write(sorted_bytes_rcvd)
except Exception as e:
print('rcv error {}'.format(e))
f.close()
服务器端发送数据
def send_img(host, port, file_name, num_pkt):
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setblocking(0)
sock.settimeout(60)
client_addr = (host, port)
# send the file name
while num_pkt > 0:
img_part = requested_file.read(BUF_SIZE + 8)
sock.sendto(img_part + seq_num)
num_pkt -= 1
您发布的代码似乎假设在从发送方到接收方的途中不会丢弃任何数据包——这个假设在现实生活中不成立(甚至不成立)当发送方和接收方都位于同一台机器上时!),这是您的传输无法正常工作的最可能原因,除非是非常小的文件(您可以依靠运气来确保所有数据包都成功通过第一次尝试)。
为了实现更健壮的机制,您的接收程序将需要一些方法来 (a) 检测数据包何时被丢弃,以及 (b) 通过将消息发送回请求发送方的发送方来对这些知识做出反应重新传输 "lost" 数据包中的数据。 (当然,重传请求数据包也可能被丢弃,因此您也需要一种方法来处理它!)
与此同时,您的发送程序不仅需要发送数据(就像它目前所做的那样),还需要从接收方接收任何传入的重传请求数据包,并通过重传请求的数据来对它们做出反应。
根据协议的具体设计,发送方和接收方可能还需要在经过一定时间后没有发送或接收数据后采取行动,以避免文件传输过程在以下情况下停滞所有接收会提前的数据包都被丢弃。
因此,您当前仅在循环中调用阻塞 sendto()
或 recvfrom()
的方法是不够的;相反,发送方和接收方都需要实现某种状态机,使它们既可以在适当的时间发送适当的数据包,又可以快速接收和处理传入的任何数据包。这通常可以通过单独的方式完成发送者和接收者线程,或者通过将套接字设置为非阻塞模式并围绕对 select()
或 poll()
的阻塞调用编写事件循环。 (我更喜欢后者,因为在我看来,虽然状态机很难做到正确,但多线程更棘手)
将序列号放入每个数据包是一个好的开始;这允许接收方知道如何对数据进行排序,并允许它检测接收到的数据中何时存在 "hole"。一旦它检测到一个漏洞(即一个或多个丢失的序列号),它可以将一个数据包发送回发送方,要求重新发送这些数据包,并且由发送方通过重新发送这些数据包来做出反应.根据需要重复,直到接收方收到一个包含所有可能序列号的数据包(您还需要以某种方式与接收方通信期望有多少序列号)。