当前位置: 首页 > 知识库问答 >
问题:

客户端无法接收UDP消息

芮瑾瑜
2023-03-14

我是一个使用python进行套接字编程的初学者。我正在做我的课程项目。我的项目的一部分需要用不同的端口发送和接收UDP消息。提供了名为robot的服务器程序,我需要编写名为student的客户端程序,它可以与机器人进行交互。因此,我不能显示服务器程序中的所有源代码。

这是服务器程序中与UDP套接字相关的部分

############################################################################# phase 3
# Create a UDP socket to send and receive data
print ("Preparing to receive x...")
addr = (localhost, iUDPPortRobot)
s3 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s3.bind(addr)

x, addr = s3.recvfrom(1)
print ("Get x = %d" % (int(x)))
############################################################################# phase 3

time.sleep(1)
print ("Sending UDP packets:")

messageToTransmit = ""
for i in range(0,int(x) * 2):
    messageToTransmit += str(random.randint(0,9999)).zfill(5)
print ("Message to transmit: " + messageToTransmit)

for i in range(0,5):
    s3.sendto(messageToTransmit.encode(),(studentIP,iUDPPortStudent))
    time.sleep(1)
    print ("UDP packet %d sent" %(i+1))
    
############################################################################# phase 4

这是我的客户端程序。s3 是 UDP 套接字。我可以成功地向服务器程序发送消息,但无法从中接收消息。这是由于端口的差异吗?如果是,我应该怎么做才能修复它?

import os
import subprocess
import socket
import random
import time

sendPort = 3310
localhost = '127.0.0.1'
socket.setdefaulttimeout(10)

command = "python robot_for_python_version_3.py"
subprocess.Popen(command)
print("ROBOT IS STARTED")

sendSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sendSocket.connect((localhost, sendPort))
studentId = '1155127379'
sendSocket.send(studentId.encode())

s_2Port = sendSocket.recv(5)
sendSocket.close()

s_2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s_2.bind((localhost, int(s_2Port)))
s_2.listen(5)
s2, address = s_2.accept()
s_2.close()

step4Port = s2.recv(12)
iUDPPortRobot, dummy1 = step4Port.decode().split(",")
iUDPPortStudent, dummy2 = dummy1.split(".")

s3 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
num = random.randint(5,10)
time.sleep(3)
s3.sendto(str(num).encode(), (localhost, int(iUDPPortRobot)))
print("Test1")

charStr = s3.recvfrom(1024)
print("Test2")
print(charStr)



exit()

共有1个答案

曾喜
2023-03-14

您没有收到消息的原因是服务器将其发送到未侦听消息的终结点。由于协议是UDP(无保证等),服务器将消息成功发送到非侦听endpoint,而侦听endpoint永远等待。

更详细地说,< code>x,addr = s3.recvfrom(1)返回的< code>addr不是< code>(studentIP,iUDPPortStudent)。尝试以下内容以查看差异(注意,您省略了定义和共享< code > iudportrobot 的部分,为了便于说明,我将其设置为50000):

# in one interactive session 1 (terminal), let's call it session 1 
>>> import socket
>>> import random 
>>> import time
>>> 
>>> iUDPPortRobot = 50000
>>> addr = ('localhost', iUDPPortRobot)
>>> s3 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
>>> s3.bind(addr)
>>> x, addr = s3.recvfrom(1) # <= this will block

# in another interactive session (terminal), let's call it session 2
>>> import socket
>>> import random 
>>> import time
>>> 
>>> iUDPPortRobot = 50000
>>> s3 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
>>> num = random.randint(5,10)
>>> s3.sendto(str(num).encode(), ('localhost', int(iUDPPortRobot))) # <= this will unblock recvfrom in session 1, i.e., the message got received
1

# back to session 1
>>> addr <= check address, this is the main issue you are facing
('127.0.0.1', 60911)
>>> messageToTransmit = ""
>>> for i in range(0,int(x) * 2):
...     messageToTransmit += str(random.randint(0,9999)).zfill(5)
... 
>>> print ("Message to transmit: " + messageToTransmit)
Message to transmit: 06729020860821106419048530205105224040360495103025

# back to session 2, let's prepare for receiving the message
>>> charStr = s3.recvfrom(1024) # <= this will block 

# back to session 1 to send a message
# you do not share what (studentIP,iUDPPortStudent), but from 
# what you describe it is not ('127.0.0.1', 60911), let's say
# studentIP = 'localhost' and iUDPPortStudent = 50001
>>> studentIP = 'localhost'
>>> iUDPPortStudent = 50001
# now let send a message that will be sent successfully but not received, i.e.,
# it will not unblock recvfrom in session 2
>>> s3.sendto(messageToTransmit.encode(),(studentIP,iUDPPortStudent))
50
# ... but if try to send to the listening endpoint it will get received
>>> s3.sendto(messageToTransmit.encode(), addr)
50

# back to session 2, to check things
>>> charStr
(b'06729020860821106419048530205105224040360495103025', ('127.0.0.1', 50000)) # <= SUCCESS

有两种方法可以解决这个问题。上面显示的方法涉及更改服务器代码,这实质上涉及上面显示的内容,即通过修改传递给< code>s3.sendto的地址将消息发送到侦听endpoint。如果我理解正确的话,这不是一个选项,因为您正在尝试编写客户端代码。第二种方法是将消息发送到< code>(studentIP,iUDPPortStudent),但在另一端有一个侦听endpoint。如果< code>studentIP和< code>iUDPPortStudent为您的“客户端”程序所知(我假设是这种情况),您可以添加类似于您在服务器程序代码片段顶部的代码。

具体地说,添加如下内容来代替charStr=s3.recvfrom(1024)

addr = (studentIP, iUDPPortStudent)
s4 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s4.bind(addr)

charStr = s4.recvfrom(1024) # <= this will block and unblock when you send the message using s3.sendto(messageToTransmit.encode(),(studentIP,iUDPPortStudent))

为了完整起见,您需要将< code>localhost更改为< code>'localhost',并且如果在您的实验中遇到< code>OSError: [Errno 98] Address已经在使用中,您将必须等待< code>TIME-WAIT周期过去,或者通过添加< code>s.setsockopt(socket)来设置< code>SO_REUSEADDR标志。SOL_SOCKET,SOCKET。SO_REUSEADDR,1)在< code>bind之前。

 类似资料:
  • 我在远程机器上设置了Kafka和动物园管理员。在那台机器上,我可以看到下面使用官方网站上的测试方法工作。 但是当我使用本地消费者脚本时,它就不起作用了: 我试着把它改成: 然后运行客户端使用者脚本,它会给出错误: [2017-08-11 15:49:01,591]获取相关id为3的元数据时警告错误:{listings-incoming=leader_not_available}(org.apach

  • 我开发了一个客户端-服务器UDP应用程序。服务器UDP套接字设置为广播UDP套接字。双方的代码不会产生任何错误,但客户端未接收到从广播UDP服务器端发送的消息。请看一下我的代码,我知道有一些错误我想不通。我真的需要帮助: 服务器: 客户: }

  • 我在实现UDP连接时遇到了麻烦,因为当我在局域网内尝试它时,它是有效的,但是当NAT内部的人试图连接到公共服务器地址时,它会失败,因为从服务器作为响应发送的数据包永远不会到达客户端。 我的协议如下: 客户端A向服务器发送一个字节作为连接请求 服务器B为客户端创建一个新的套接字,并从那里向recvfrom()调用中报告的客户端端口响应一个字节。永远不会联系到客户 我也试过: 执行许多调用,每个调用在

  • 我正在尝试使用UDP在服务器(在公共IP上)和客户端(通过NAT)之间进行双向通信。我的逻辑是,如果服务器向IP和它接收数据包的端口发送一些数据,客户端仍然应该得到它,因为NAT最终会有将数据包发送到客户端的映射。 客户端有 2 个进程,一个用于发送数据包,另一个进程用于接收数据。服务器继续等待数据,如果它获得数据,它会将数据发送回从接收数据的端口和 IP。 客户代码如下: client_recv

  • 我已经在互联网上搜索了一两个星期,想找到一个UDP客户端程序,它可以同时发送和接收数据,但是对于c#来说,没有关于这个主题的内容。在过去的几天里,我尝试创建一个UDP客户端,其中包含一个接收数据的线程。 发送UDP数据包效果很好,但程序无法接收我发送到的服务器,我相信服务器正在将所有数据包发送到不同的端口。 我如何修复这个程序? 有没有一种更简单的方法来进行UDP编程,比如用于TCP的Stream

  • 我刚刚开始学习Java。我修改了服务器/客户端通信程序的客户端代码,为客户端创建了两个线程,一个是用于接收用户输入的主线程,另一个是用于接收服务器响应的inputThread。我确信服务器已经向客户机发送了响应,但是,在客户机上没有获得响应消息。 这是我的代码。有谁能帮我弄明白吗?谢谢