我是python的新手,目前使用select的非阻塞调用来处理客户端和服务器端脚本。这是为了可靠地将文件从客户端发送到服务器,即使在丢包时也是如此。我不想使用预先存在的模块,如Twisted或Eventlet
我假设没有数据包损坏延迟,但只有丢弃以随机方式发生。我将仅在服务器端构建drop simulation功能,它将是'传入数据包丢弃功能(服务器将数据保存到来自套接字的'dummy'变量,具有随机概率,因此套接字不可读并且进度停止直到新数据包到来in)'和'传出ACK丢弃功能(即使服务器接收到数据并将数据写入文件,ACK也不发送,或发送但客户端未到达)。我已经构建了第一个,但还没有建立ACK丢弃功能。
到现在为止,我可以在没有丢包的情况下发送文件。但是,当数据包丢失时,我希望我的客户端等待几秒钟并一次又一次地发送包含相同数据的数据包,直到它从服务器收到先前发送的数据包的ACK。但是当服务器模拟丢包时,客户端功能就会停止工作。我认为我的代码有问题需要建议。除此之外,我很乐意为编写这些代码的最佳实践提供任何反馈。谢谢。
以下是我到目前为止所做的事情。对不起我顺便说一下我的编码方式:(
客户端
import socket
import sys
import select
import time
host = ''
port = 1238
buf = 9216 # Jumboframe
addr = (host, port)
p_cnt = 0
read_cnt = 0
response_cnt = 0
response = ('','')
data = ''
# Socket Creation, binding
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('', 9996))
# Receive file name from user
file_name = "lol.png" # raw_input("Enter the name of the file: ")
f = open(file_name, "rb")
readable = [s, f]
writable = [s]
prev_data = file_name
while s:
try:
rd, wt, er = select.select(readable, writable, [], 0)
# When readable
for rsk in rd:
if rsk is s: # When socket is readable (3. Receive ACK from packet)
if p_cnt > response_cnt: # If sent packets > received response
response = s.recvfrom(buf) # Receive response from server
response_cnt += 1 # Increase the response counter by 1
print response[0] # Printout the received response
else: # When socket is not readable
if read_cnt > response_cnt: # When there is any data that has been read from file but not sent yet
start_time = time.time() # Start checking time
while 1:
if time.time() - start_time == 3: # When 3 second has been passed since the start time
print "Seems packet has been dropped, resending " + str(p_cnt) + " packet"
#for wsk in wt:
# if wsk is s:
s.sendto(data, addr) # Send the packet again
break # And break
# When readable
for rsk in rd:
if rsk is f: # When file is readable (2. Read data from FILE)
if response_cnt > read_cnt: # If received response > file read
data = f.read(buf) # Read more file
read_cnt += 1 # And Increase the read counter by 1
if data: # If there is a data read from file in buffer,
# print how many times it read the file
#if p_cnt > response_cnt:
# prev_data = data
print "Reading file...(" + str(read_cnt) + ")"
else: # If there is no data in the buffer,
# print there is no more data to send and close fileIO
print "No more data"
# When writable
for wsk in wt:
if wsk is s: # If socket is writable (1. Send data to server)
# If there is no packet sent to the server before
if p_cnt == 0:
# This is the sending the first packet includes file name
print "Sending file name"
# Send the file name to the server
s.sendto(file_name, addr)
# Print we sent the file name to server
print "File name sent"
p_cnt += 1 # And increase sent packet counter by 1
else: # If it's not a first packet to send
# If reading counter is same as packet counter,
# which mean we received response for what we sent
if read_cnt == p_cnt:
# If there is a data to send to server in the buffer
if(data):
# Send that data to the server
s.sendto(data, addr)
# And print out we just sent the data
print "Sent " + str(p_cnt) + " packet"
# And increase the sent packet counter by 1
p_cnt += 1
else: # If there is no data to send
# Sending empty data to let server know EOF
print "Sending EOF"
s.sendto("EOF", addr)
#s.sendto(data, addr)
p_cnt += 1
if response[0] == "ACK EOF":
print "Transmission complete" # Print the status
break
except socket.error, msg:
print 'Error Code : ' + str(msg[0]) + ' - ' + msg[1]
sys.exit()
f.close()
s.close() # Close the socket
sys.exit()
服务器端
import socket
import sys
import select
import random
host = ''
port = 1238
buf = 9216 # Jumboframe
p_cnt = 0
response_cnt = 0
write_cnt = 0
dummy = ''
p1 = 0.8 # Probability that the packet will be dropped
# Socket creation, binding
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((host, port))
# Start waiting for the socket
print "Waiting for incoming"
data, addr = s.recvfrom(buf) # Blocking
# Received first packet that contains file name
print "Received File: ", data.strip()
p_cnt += 1
file_name = data.strip()
f = open(file_name, "wb")
readable = [s]
writable = [s, f]
while s:
try:
rd, wt, er = select.select(readable, writable, [], 0)
response = "ACK " + str(p_cnt)
# When readable
for rsk in rd:
if rsk is s: # When socket is readable (1. Receive data)
# If there's only one packet received and no file written
if p_cnt == 1 and write_cnt == 0:
##############################################################################
if int(random.random() >= p1) == 1:
# Incoming packet dropped - Make socket unreadable
dummy, addr = s.recvfrom(buf)
print "Incoming packet " + str(p_cnt+1) + " dropped"
##############################################################################
else:
# Read the received data from socket
data, addr = s.recvfrom(buf)
# Print how many packet has been received until now
print "Received " + str(p_cnt) + " packet"
# If it's not the first packet or data has been written before
else: # If the number of received packet = number of sent ACK
# responsed to all the received packets to the client
if p_cnt == response_cnt:
##############################################################################
if int(random.random() >= p1) == 1:
# Incoming packet dropped - Make socket unreadable
dummy, addr = s.recvfrom(buf)
print "Incoming packet " + str(p_cnt+1) + " dropped"
##############################################################################
else:
# Read more data from socket and save to buffer
data, addr = s.recvfrom(buf)
# And increase the received packet counter by 1
p_cnt += 1
if data: # If there is data to read from socket,
# Print out how many packet that we have received
print "Received " + str(p_cnt) + " packet"
else: # If there is no data to read from socket,
# Print out there is no more data to read
print "No more data, closing file"
# When writable
for wsk in wt:
# When socket is writable (3. Send ACK)
if wsk is s:
# If number of writing times > number of ACK sent
if write_cnt > response_cnt:
# Send ACK to client
s.sendto(response, addr)
# And increase number of ACK sent
response_cnt += 1
# When file is writable (2. Write on FILE)
if wsk is f:
# If number of packet received > number of file writing
if p_cnt > write_cnt:
# If there is data to write in the buffer
if data and data != "EOF":
# And if it's not the first packet(file name, which shouldn't be written in file)
if p_cnt != 1:
f.write(data) # Write buffer to the file
write_cnt += 1 # And increase write counter
# Print how many times the buffer has been writted
print "Wrote " + str(p_cnt) + " packet"
else: # If there is no data to write in the buffer
print "Sending ACK EOF"
s.sendto("ACK EOF", addr)
if data == "EOF":
print "File Downloaded" # Print out the file download completed
break
except socket.error, msg:
print 'Error Code : ' + str(msg[0]) + ' - ' + msg[1]
sys.exit()
f.close()
s.close() # Close the socket
sys.exit()
答案 0 :(得分:0)
客户的行
else: # When socket is not readable
错误 - else
属于if rsk is s
,因此在rsk is f
条件下达到,{i}即当文件可读时。
然后,下一行
if read_cnt > response_cnt: # When there is any data that has been read from file but not sent yet
错误 - read_cnt
最多等于,但绝不会超过response_cnt
,因为只有
if response_cnt > read_cnt: # If received response > file read
data = f.read(buf) # Read more file
read_cnt += 1 # And Increase the read counter by 1
增加read_cnt
。
我建议从f
删除readable
,并假设文件在必要时可读,以及从s
删除writable
以及移动文件名的发送while s:
循环之前的数据包,在select
呼叫中丢弃忙等待并使用超时 3;然后你可以在超时时再次发送数据包。