客户端(python 程序)没有收到服务器(c 程序)返回的响应?
Client (python program) does not receive a response back from the server (c program)?
我有一个在服务器端工作的 UDP 套接字应用程序。为了测试服务器端,我编写了一个发送消息 "hello world how are you" 的简单 python 客户端程序。服务器随后应接收消息,将其转换为大写并发送回客户端。问题就在这里:我可以在调试时观察到服务器正在接收消息、应用转换、发回响应并最终等待另一条消息。但是 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");
}
}
}
同样的问题是我没有收到响应,也没有在客户端打印回消息。我应该收到所有大写字母的相同消息。我觉得我错过了一个小细节。感谢您的帮助!
又快又脏:
从您的 C 代码中删除这一行:
claddr.sin_port = htons(PORT_NUM);
现在为什么:
当您在 python 脚本中发送消息时,您的操作系统将用您指定的目标 IP 地址和端口填充 UDP packet,您正在使用的机器的 IP 地址源 IP 字段,最后是 OS 分配的源端口 "randomly"。请注意,这与目标端口不是同一个端口,即使是这样,您怎么知道哪个程序将收到源消息?(两者都会听到来自同一端口的消息)幸运的是,这不是可能。
现在,当您的 C 代码收到此数据包时,它会知道是谁发送了消息,并且您可以通过 recvfrom 填充的 sockaddr 结构访问此信息。如果你想发回一些信息,你必须发送一个目标端口(服务器看到的)等于客户端看到的源端口的数据包,这又不是你正在监听的相同端口服务器。通过执行 claddr.sin_port = htons(PORT_NUM)
,您设置用服务器端口覆盖包含客户端源端口的字段,当您尝试发送此数据包时,可能会发生两件事:
- 如果客户端运行来自同一台电脑,目的IP和
源 IP 将相同,您刚刚设置了目标端口
成为服务器正在侦听的端口,因此您将拥有一个
消息循环。
- 如果运行在不同的电脑上,数据包会
由客户端计算机收到,但可能不会有任何
程序在该端口上等待消息,因此它被丢弃。
一个半生不熟的比喻:你收到朋友的一封信,但是给他回信的时候,你把他的门牌号改成了你家的门牌号……没有多大意义。唯一不同的是,你这位朋友的动作比较大,每个字母的数字可能不同,但这不重要。
理论上,如果要接收回数据就必须bind,此时bind相当于监听那个端口。这个答案阐明了为什么在这种情况下没有必要:
如果您在 linux,您可以使用 sudo ss -antup | grep python
查看您 OS 分配给 UDP 套接字的端口
N。 Dijkhoffz,很想听听您是如何修复它的,也许 post 正确的代码。
我有一个在服务器端工作的 UDP 套接字应用程序。为了测试服务器端,我编写了一个发送消息 "hello world how are you" 的简单 python 客户端程序。服务器随后应接收消息,将其转换为大写并发送回客户端。问题就在这里:我可以在调试时观察到服务器正在接收消息、应用转换、发回响应并最终等待另一条消息。但是 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");
}
}
}
同样的问题是我没有收到响应,也没有在客户端打印回消息。我应该收到所有大写字母的相同消息。我觉得我错过了一个小细节。感谢您的帮助!
又快又脏:
从您的 C 代码中删除这一行:
claddr.sin_port = htons(PORT_NUM);
现在为什么:
当您在 python 脚本中发送消息时,您的操作系统将用您指定的目标 IP 地址和端口填充 UDP packet,您正在使用的机器的 IP 地址源 IP 字段,最后是 OS 分配的源端口 "randomly"。请注意,这与目标端口不是同一个端口,即使是这样,您怎么知道哪个程序将收到源消息?(两者都会听到来自同一端口的消息)幸运的是,这不是可能。
现在,当您的 C 代码收到此数据包时,它会知道是谁发送了消息,并且您可以通过 recvfrom 填充的 sockaddr 结构访问此信息。如果你想发回一些信息,你必须发送一个目标端口(服务器看到的)等于客户端看到的源端口的数据包,这又不是你正在监听的相同端口服务器。通过执行 claddr.sin_port = htons(PORT_NUM)
,您设置用服务器端口覆盖包含客户端源端口的字段,当您尝试发送此数据包时,可能会发生两件事:
- 如果客户端运行来自同一台电脑,目的IP和 源 IP 将相同,您刚刚设置了目标端口 成为服务器正在侦听的端口,因此您将拥有一个 消息循环。
- 如果运行在不同的电脑上,数据包会 由客户端计算机收到,但可能不会有任何 程序在该端口上等待消息,因此它被丢弃。
一个半生不熟的比喻:你收到朋友的一封信,但是给他回信的时候,你把他的门牌号改成了你家的门牌号……没有多大意义。唯一不同的是,你这位朋友的动作比较大,每个字母的数字可能不同,但这不重要。
理论上,如果要接收回数据就必须bind,此时bind相当于监听那个端口。这个答案阐明了为什么在这种情况下没有必要:
如果您在 linux,您可以使用 sudo ss -antup | grep python
N。 Dijkhoffz,很想听听您是如何修复它的,也许 post 正确的代码。