Клиент (программа python) не получает ответ обратно с сервера (c программой)?

1

У меня есть приложение сокета UDP, где я работаю на стороне сервера. Для тестирования серверной части я собрал простую клиентскую программу на 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");
        }
    }
}

Опять проблема в том, что я не получаю ответ и не печатаю сообщение обратно на клиентском терминале. Я должен получить одно и то же сообщение заглавными буквами. Я чувствую, что мне не хватает маленькой детали. Спасибо за помощь!

  • 0
    У меня уже была похожая проблема, и я решаю ее, посылая символ '\ 0' в конце ответа, чтобы указать конец сообщения.
  • 1
    @EduardoSoares не должен sendto присоединить '\ 0' к концу сообщения? Несмотря на это; Я думаю, что recv в программе на python должен, по крайней мере, печатать то, что он получает. Я попробую на всякий случай, если это проблема.
Показать ещё 2 комментария
Теги:
sockets
udp

1 ответ

1

Быстро и грязно:

Удалите эту строку из вашего кода C:

claddr.sin_port = htons(PORT_NUM);

Теперь почему:

Когда вы отправляете сообщение в своем скрипте Python, ваша операционная система заполнит пакет UDP с указанным IP-адресом назначения и портом, IP-адресом машины, которую вы используете в поле исходного IP-адреса, и, наконец, назначенным исходным портом. "случайно" ОС. Обратите внимание, что это не тот порт, который является портом назначения, и даже если бы это было так, как бы вы узнали, какая программа получит исходное сообщение (обе будут слушать сообщения с одного и того же порта) К счастью, это не так возможный.

Теперь, когда ваш C-код получит этот пакет, он будет знать, кто отправил сообщение, и у вас есть доступ к этой информации через структуру sockaddr, заполненную recvfrom. Если вы хотите отправить некоторую информацию обратно, вы должны отправить пакет с портом назначения (который видит сервер), равным порту источника, который видит клиент, который, опять же, не совпадает с портом, который вы слушаете на сервер. Делая claddr.sin_port = htons(PORT_NUM), вы устанавливаете перезапись поля, содержащего исходный порт клиента, на порт сервера, и при попытке отправить этот пакет могут произойти 2 вещи:

  • Если клиент работал с того же компьютера, IP-адрес назначения и IP-адрес источника будут одинаковыми, и вы просто установите порт назначения в качестве порта, который прослушивает сервер, поэтому у вас будет цикл обработки сообщений.
  • При запуске на разных компьютерах пакет будет получен клиентским компьютером, но, вероятно, не будет никаких программ, ожидающих сообщений на этом порту, поэтому он отбрасывается.

Недоделанная аналогия: вы получаете письмо от друга, но, переписываясь с ним, вы меняете номер его дома на номер вашего дома... не имеет особого смысла. Разница лишь в том, что ваш друг много двигается, и каждая буква может иметь разное число, но это не важно.

Теоретически, вы должны выполнить привязку, если хотите получить данные обратно, в этом случае привязка эквивалентна прослушиванию этого порта. Этот ответ разъясняет, почему это не было необходимо в этом случае: qaru.site/questions/282917/...

Если вы работаете в Linux, вы можете увидеть, какой порт вашей ОС назначен для вашего сокета UDP, используя sudo ss -antup | grep python sudo ss -antup | grep python

  • 0
    Спасибо за подробное объяснение. Я понимаю вашу точку зрения. Я удалил строку кода. Однако клиент все еще не получает ответ. Должен ли я тогда попытаться привязать клиента к серверу? Опять же, то, что вы говорите, имеет смысл, но достаточно просто удалить строку и отправить ответ на тот же порт, на который было получено сообщение. Связывание не требуется.
  • 0
    Просто чтобы уточнить, нет привязки к серверу. UDP - это протокол без установления соединения, вы отправляете сообщения и забываете о них. Когда мы говорим о связывании здесь, мы связываемся с портом в интерфейсе вашего компьютера, поэтому ОС сообщает нам о полученных там пакетах. Затем сервер отправит ответы на этот адрес. Насчет вашей проблемы, странно, я скопировал код и протестировал его здесь перед публикацией, он работал после смены IP и удаления строки. Вы на Linux? Если это так, сделайте sudo ss -antup | grep python когда клиент ожидает ответа. Кроме того, опубликовать вывод вашего сервера.
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню