客户端(python程序)没有收到来自服务器(c程序)的响应?

时间:2019-01-22 15:37:58

标签: python c sockets udp

我有一个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");
        }
    }
}

同样的问题是我没有收到响应,而是在客户端上打印了消息。我应该收到所有大写字母的相同消息。我觉得我缺少一个小细节。感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

又快又脏:

从您的C代码中删除此行:

claddr.sin_port = htons(PORT_NUM);

现在为什么:

当您使用python脚本发送消息时,操作系统将在UDP packet中填充您指定的目标IP地址和端口,源IP字段上正在使用的计算机的IP地址以及最后,由操作系统“随机”分配的源端口。请注意,这与目标端口不是同一端口,即使是这种情况,您如何知道哪个程序将接收源消息?(两者都将从同一端口接收消息)幸运的是,这不是可能。

现在,当您的C代码收到此数据包时,它将知道谁发送了该消息,并且您可以通过recvfrom填充的sockaddr结构访问此信息。如果要发回一些信息,则必须发送的数据包的目标端口(如服务器所示)等于客户端所看到的源端口,该端口与您正在侦听的端口相同。服务器。通过执行claddr.sin_port = htons(PORT_NUM),您设置了用服务器端口覆盖包含客户端源端口的字段,并且当您尝试发送此数据包时,可能会发生两种情况:

  • 如果客户端从同一台计算机运行,则目标IP和 源IP将相同,并且您已经设置了目标端口 成为服务器正在监听的端口,因此您将拥有一个 消息循环。
  • 如果在其他计算机上运行,​​则该数据包将是 客户端计算机收到的邮件,但可能不会 程序在该端口上等待消息,因此将其丢弃。

一个半生半熟的比喻:您收到一位朋友的来信,但是当给他回信时,您用他的房子号码来改变他的房子号码……没有什么意义。唯一的不同是,您的这个朋友移动很多,每个字母的数字可能不同,但这并不重要。

理论上,如果要接收回数据,则必须绑定,在这种情况下,bind等效于监听该端口。该答案阐明了为什么在这种情况下没有必要的原因:https://stackoverflow.com/a/14243544/6253527

如果您使用的是Linux,则可以使用sudo ss -antup | grep python

查看操作系统为UDP套接字分配的端口。

答案 1 :(得分:0)

N。 Dijkhoffz,很想听听您如何解决它,并可能发布正确的代码。