我有一个UDP套接字应用程序,我在服务器端工作。为了测试服务器端,我组合了一个简单的python客户端程序,该程序发送消息“ hello world,你好吗”。然后,服务器应接收到消息,将其转换为大写并发送回客户端。问题就在这里:在调试服务器时,我可以观察到服务器正在接收消息,应用转换,将响应发送回并最终等待另一条消息。但是python客户端没有收到消息,而是无休止地等待服务器的响应。
我通过网络发现(一种选择),为了使客户端接收回响应,它需要绑定到服务器,这与我在教科书(Linux编程接口)中所看到的背道而驰。但是,我尝试将客户端绑定到服务器,而python程序无法在绑定行上连接(不知道我是否正确执行了操作)。 Python版本是2.7.5。客户端程序在RedHat上运行,服务器在Angstrom(针对32位处理器进行交叉编译)的目标模块上运行。
这是客户端的代码:
import socket
import os
UDP_IP = "192.168.10.4"
UDP_PORT = 50005
#dir_path = os.path.dirname(os.path.realpath(__file__))
MESSAGE = "hello world how are you"
print "UDP target IP: ", UDP_IP
print "UDP target port: ", UDP_PORT
print "message: ", MESSAGE
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#sock.bind((UDP_IP, UDP_PORT))
print "Sending message..."
sock.sendto(MESSAGE, (UDP_IP, UDP_PORT))
print "Message sent!"
print "Waiting for response..."
data = sock.recv(1024)
print "Received", repr(data)
这是服务器的代码:
void server_side(void)
{
printf("Server start up.\n");
struct sockaddr_in svaddr;
struct sockaddr_in claddr;
int sfd;
int j;
ssize_t numBytes;
socklen_t len;
char buf[BUF_SIZE];
char claddrStr[INET_ADDRSTRLEN];
//int output = open("test_output.txt", O_WRONLY|O_CREAT, 0664);
printf("Creating new UDP socket...\n");
sfd = socket(AF_INET, SOCK_DGRAM, 0); /* Create Server Socket*/
if (sfd == -1)
{
errExit("socket");
}
printf("Socket has been created!\n");
memset(&svaddr, 0, sizeof(struct sockaddr_in));
svaddr.sin_family = AF_INET;
svaddr.sin_addr.s_addr = htonl(INADDR_ANY);
svaddr.sin_port = htons(PORT_NUM);
printf("Binding in process...\n");
if (bind(sfd, (struct sockaddr *) &svaddr, sizeof(struct sockaddr_in))
== -1)
{
errExit("bind");
}
printf("Binded!\n");
/* Receive messages, convert to upper case, and return to client.*/
for(;;)
{
len = sizeof(struct sockaddr_in);
numBytes = recvfrom(sfd, buf, BUF_SIZE, 0,
(struct sockaddr *) &claddr, &len);
if (numBytes == -1)
{
errExit("recvfrom");
}
if (inet_ntop(AF_INET, &claddr.sin_addr, claddrStr,
INET_ADDRSTRLEN) == NULL)
{
printf("Couldn't convert client address to string.\n");
}
else
{
printf("Server received %ld bytes from (%s, %u).\n", (long)
numBytes,
claddrStr, ntohs(claddr.sin_port));
}
claddr.sin_port = htons(PORT_NUM);
for (j = 0; j< numBytes; j++)
{
buf[j] = toupper((unsigned char) buf[j]);
}
if (sendto(sfd, buf, numBytes, 0, (struct sockaddr *) &claddr, len)
!= numBytes)
{
fatal("sendto");
}
}
}
同样的问题是我没有收到响应,而是在客户端上打印了消息。我应该收到所有大写字母的相同消息。我觉得我缺少一个小细节。感谢您的帮助!
答案 0 :(得分:1)
又快又脏:
从您的C代码中删除此行:
claddr.sin_port = htons(PORT_NUM);
现在为什么:
当您使用python脚本发送消息时,操作系统将在UDP packet中填充您指定的目标IP地址和端口,源IP字段上正在使用的计算机的IP地址以及最后,由操作系统“随机”分配的源端口。请注意,这与目标端口不是同一端口,即使是这种情况,您如何知道哪个程序将接收源消息?(两者都将从同一端口接收消息)幸运的是,这不是可能。
现在,当您的C代码收到此数据包时,它将知道谁发送了该消息,并且您可以通过recvfrom填充的sockaddr结构访问此信息。如果要发回一些信息,则必须发送的数据包的目标端口(如服务器所示)等于客户端所看到的源端口,该端口与您正在侦听的端口相同。服务器。通过执行claddr.sin_port = htons(PORT_NUM)
,您设置了用服务器端口覆盖包含客户端源端口的字段,并且当您尝试发送此数据包时,可能会发生两种情况:
一个半生半熟的比喻:您收到一位朋友的来信,但是当给他回信时,您用他的房子号码来改变他的房子号码……没有什么意义。唯一的不同是,您的这个朋友移动很多,每个字母的数字可能不同,但这并不重要。
理论上,如果要接收回数据,则必须绑定,在这种情况下,bind等效于监听该端口。该答案阐明了为什么在这种情况下没有必要的原因:https://stackoverflow.com/a/14243544/6253527
如果您使用的是Linux,则可以使用sudo ss -antup | grep python
答案 1 :(得分:0)
N。 Dijkhoffz,很想听听您如何解决它,并可能发布正确的代码。