Python中的套接字编程

时间:2015-02-20 15:36:19

标签: python sockets udp

我正在使用python进行概念验证,模拟使用套接字发送UDP数据包的服务器/客户端通信。我可以很容易地做一个简单的客户端服务器和回到客户端通信,但我正在尝试介绍一个"中间人"进入那种沟通。从概念上讲,问题可以被描述为,如果" Joe"是主要的客户,他会向史蒂夫"发送消息。谁是中间人,他会在发送给#Car;" Carol"谁充当服务器,将处理新消息并将响应发送给中间人,#34;史蒂夫"。最终,中间人将在其他地方发送该消息,但此刻我并不担心这一点。

我目前的代码如下:

" Joe" (原始客户端)看起来像

# 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毫秒,我原本以为将乔的最新数据包缓存在本地内存位置并覆盖该位置,直到史蒂夫准备发送一个一旦她用最后一个数据包回复,她就会收到一些信息。但是,对于这个简单的概念证明,我还没有尝试过这样做。对此的任何建议也会有所帮助。

1 个答案:

答案 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在丢失之后不会发送任何新数据包。如前所述,由于乔尽可能快地将数据包爆破,因此数据包丢失的可能性更大。

要检测数据包丢失,有几个选项:

  • 使用多个threadsprocesses进行发送和接收。这将使您的程序更加复杂。
  • 切换到异步/非阻塞IO,在Python中使用高级asyncore或更低级别select
  • 设置并正确处理socket timeouts。这可能是目前最简单的选择,但是非常有限。
  • 如果您确实需要可靠的通信,请切换到TCP。

除上述网络问题外,还存在一些潜在问题或不准确之处:

  • 如果您使用的是Python 2.x,decodeencode对字符串的行为取决于系统配置。像许多其他潜在的问题一样,这已经在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')