我正在使用python进行概念验证,模拟使用套接字发送UDP数据包的服务器/客户端通信。我可以很容易地做一个简单的客户端服务器和回到客户端通信,但我正在尝试介绍一个"中间人"进入那种沟通。从概念上讲,问题可以被描述为,如果" Joe"是主要的客户,他会向史蒂夫"发送消息。谁是中间人,他会在发送给#Car;" Carol"谁充当服务器,将处理新消息并将响应发送给中间人,#34;史蒂夫"。最终,中间人将在其他地方发送该消息,但此刻我并不担心这一点。
我目前的代码如下:
# create dgram udp socket
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
except socket.error:
print ('Failed to create socket')
sys.exit()
host = 'localhost'
port = 8888
print("start comms")
while 1:
arr = ['Dog', 'cat', 'treE', 'Paul']
num = random.randrange(0,4)
#Send the string
s.sendto(arr[num].encode(), (host, port))
host = ''
hostRT = 'localhost'
portVM = 8888
portRT = 8752
# socket to receive from "Joe"
s1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s1.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s1.bind((host, portVM))
# socket to send to "Carol"
s2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
print("start comms")
while 1:
# receive from "Joe"
data = s1.recvfrom(1024)
num = data[0].decode()
addrVM = data[1]
# print data from Joe
print(num)
# add some excitement to Joe's message
num += '!!!'
# show received message address + port number
print ("message[" + addrVM[0] + ":" + str(addrVM[1]) + ']')
# Send to "Carol"
s2.sendto(num.encode(), (hostRT, portRT))
# receive from "Carol"
d = s2.recvfrom(1024)
reply = d[0].decode()
addrRT = d[1]
# show received message address + port number
print ("message[" + addrRT[0] + ":" + str(addrRT[1]) + ']')
# show Carol's response
print ('Server reply : ' + reply)
s1.close()
s2.close()
host = ''
port = 8752
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
print ("socket created")
s.bind((host, port))
print ("Socket bind complete")
while 1:
d = s.recvfrom(1024)
data = d[0].decode()
addr = d[1]
print(data)
reply = "Upper case client data = " + data.upper()
print(reply)
s.sendto(reply.encode(), addr)
print ("message[" + addr[0] + ":" + str(addr[1]) + '] - ' + data.strip())
s.close()
目前我可以收到来自Joe的消息但是它会挂起发送到服务器Carol。我对套接字编程完全陌生,所以非常感谢任何帮助。
使用Python 3.4
Joe正在不停地发送数据包,以模拟此概念验证所适用的实际应用程序。 Joe将以大约1个数据包/ 4毫秒的速率发送数据包,但我只关心最新的数据包。然而,由于从史蒂夫到卡罗尔往返的平均周转时间约为10毫秒,我原本以为将乔的最新数据包缓存在本地内存位置并覆盖该位置,直到史蒂夫准备发送一个一旦她用最后一个数据包回复,她就会收到一些信息。但是,对于这个简单的概念证明,我还没有尝试过这样做。对此的任何建议也会有所帮助。
答案 0 :(得分:3)
有多个故障导致整体故障,其中一些故障并不明显(即它会在其他地方崩溃之前有效)。
首先,此刻发送数据包的速度尽可能快。仅此一项就可能导致其他地方的数据包丢失(这可能是一件好事,因为您现在必须确保您的代码能够在数据包丢失的情况下继续存在)。除非你真的想强调网络,否则time.sleep(0.1)
之类的东西在发送循环中是合适的。
更重要的是,史蒂夫的套接字设置都搞砸了。他最多需要两个插座,而不是三个插座。它目前的设置方式,carol回答了她收到数据包的IP地址和端口(这是非常明智的),但史蒂夫读取了一个永远不会发送数据的独特套接字。
更糟糕的是,端口史蒂夫的s3
侦听实际上与卡罗尔使用的是同一个!因为你是not using multicast。您只需从代码中删除对s3
的每个引用,并专门使用s2
。
另一个问题是您不处理丢包问题。例如,如果数据包在steve和carol之间丢失,则代码
# Send to "Carol"
s2.sendto(num.encode(), (hostRT, portRT))
# receive from "Carol"
d = s2.recvfrom(1024) # s3 in the original
将永远挂起,因为Carol在丢失之后不会发送任何新数据包。如前所述,由于乔尽可能快地将数据包爆破,因此数据包丢失的可能性更大。
要检测数据包丢失,有几个选项:
除上述网络问题外,还存在一些潜在问题或不准确之处:
decode
和encode
对字符串的行为取决于系统配置。像许多其他潜在的问题一样,这已经在Python 3.x中通过强制使用UTF-8来修复(在2.x中你必须明确要求)。在你的情况下,只要你只发送ASCII字符就没问题。while(1) :
在Python中看起来很奇怪 - 为什么在参数之后的空白,以及为什么用圆括号。为什么不while 1:
或while True:
?您可以使用tuple unpacking效果很好。而不是
data = s1.recvfrom(1024) num = data [0] .decode() addrVM = data [1]
怎么样:
data, addrVM = s1.recvfrom(1024)
num = data.decode('utf-8')