客户端(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 正确的代码。