recvf с повторного чтения данных на сокете

Я создаю простую программу сокета сервера / клиента UDP и столкнулся с проблемой.

Проблема в том, что функция recvfrom() продолжает перечитывать последние отправленные данные.

Поэтому, если я отправлю два пакета с клиента на сервер, то recvfrom() будет считывать первый пакет и распечатывать его данные, а затем будет постоянно читать второй пакет снова и снова.

Как я понимаю, пакет должен быть удален из сокета после успешной операции чтения, но этого, похоже, не происходит.

Я точно знаю, что клиент не пересылает данные, так как есть консольный вывод, который записывается всякий раз, когда клиент отправляет данные.

Вот функция для отправителя

int sendPacket(int socketFd, int type, char *typeString, char *data, int seq, int     windowSize, struct sockaddr_in serverName) {

    struct packet *sendPacketPtr, sendPacket;
    fd_set writeFdSet;

    sendPacketPtr = &sendPacket;

    sendPacket.flags = type;
    sendPacket.windowsize = windowSize;
    sendPacket.seq = seq;
    sendPacket.id = getpid();

    if (type == NORMAL)
        strcpy(sendPacket.data, data);

    FD_ZERO(&writeFdSet);
    FD_SET(socketFd, &writeFdSet);

    if(select(FD_SETSIZE, NULL, &writeFdSet, NULL, NULL) > 0) {
        if(sendto(socketFd, sendPacketPtr, sizeof(sendPacket), 0, (struct sockaddr     *)&serverName, sizeof(serverName)) < 0) {
            printf("%s packet was not sent\n", typeString);
            perror("Send error");
        } else {
            printf("%s packet was sent\n", typeString);
        }
    }

    return 0;
}

Который вызывается с этим циклом, который запускается дважды для его заданных значений.

for (int i = seqBase; i <= seqMax && i < packetNum; i++) {
      sendPacket(socketFd, NORMAL, "DATA", dataArray[i], i, 0, serverName);
}

И функция получения

struct packet receivePacket (int socketFd, struct sockaddr_in *address, int timeout,     int useTimeout) {

    struct packet buffer;
    fd_set readFdSet;
    struct sockaddr_in dest_addr;

    struct timeval selectTimeout;
    selectTimeout.tv_usec = 0;
    selectTimeout.tv_sec = timeout;

    FD_ZERO(&readFdSet);
    FD_SET(socketFd, &readFdSet);

    socklen_t len = sizeof(dest_addr);

    if(useTimeout == 0) {
        if(select(FD_SETSIZE, &readFdSet, NULL, NULL, NULL) > 0) {
            if(recvfrom(socketFd, &buffer, sizeof(buffer), 0, (struct sockaddr     *)&dest_addr, &len) < 0) {
                perror("Read error");
            }else {
                *address = dest_addr;
            }
        }
    }else {
        if(select(FD_SETSIZE, &readFdSet, NULL, NULL, &selectTimeout) > 0) {
            if(recvfrom(socketFd, &buffer, sizeof(buffer), 0, (struct sockaddr     *)&dest_addr, &len) < 0) {
                perror("Read error");
            }else {
                *address = dest_addr;
            }
        }
    }

    return buffer;

}

Который вызывается с этим циклом с сервера

receivedPacket = receivePacket(socketFd, &destAddress, 0, 0);
while (receivedPacket.flags == NORMAL) {
      printf("Data received: \"%s\", sequence: %d\n", receivedPacket.data, receivedPacket.seq);
      receivedPacket = receivePacket(socketFd, &destAddress, TIMEOUT, 1);
}

И вывод, который выполняется вечно (поскольку он продолжает перечитывать последний пакет):

Data received: "Packet 0", sequence: 0
Data received: "Packet 1", sequence: 1
Data received: "Packet 1", sequence: 1
Data received: "Packet 1", sequence: 1
Data received: "Packet 1", sequence: 1
........

1 ответ

Решение
  1. В случаях сбоя (т. Е. Если recvfrom или когда select возвращает по тайм-ауту), вы также возвращаете "буфер", который не инициализирован, поэтому его содержимое может быть предваряющим данными, но поведение не определено. Поэтому лучше инициализировать его до 0 (memset(&buffer,0,sizeof(struct packet))) в начале, прежде чем вызывать recvfrom

  2. В цикле while вы проверяете (receivePacket.flags == NORMAL), если NORMAL
    только тогда вы печатаете буфер и снова вызываете функцию.

    В функции "receivePacket" по истечении времени ожидания или "recvfrom сбоя (ов)" обновите "receivePacket.flags", чтобы изменить NORMAL так, чтобы цикл находился в процессе прерывания.

Другие вопросы по тегам