recvfrom re-reading data on socket

2019-09-20 02:06发布

I'm creating a simple server/client UDP socket program and I've run into a problem.

The problem is that the recvfrom() function keeps on re-reading the last data that was sent.

So if I send two packets from the client to the server then recvfrom() will read the first packet and print its data then it will constantly read the second packet over and over again.

As I understand it the packet should be removed from the socket once a successful read operation has been performed, but that doesn't seem to be happening.

I know for a fact that the client isn't resending the data since there's a console output that is written whenever the client sends data.

Here's the function for the sender

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;
}

Which is called with this loop which runs twice for its given values.

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

And the receiving function

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;

}

Which is called with this loop from the server

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);
}

And the output which which runs forever (since it keeps re-reading the last packet) is:

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条回答
爷的心禁止访问
2楼-- · 2019-09-20 02:50
  1. In the failure cases (i.e if recvfrom or when select returns on timeout) also you are returning "buffer" which is not initialized so the contents can be previsous data but the behaviour is undefined. So it is better you initialize it to 0 (memset(&buffer,0,sizeof(struct packet))) in the begining before calling recvfrom

  2. In the while loop you are checking for (receivedPacket.flags == NORMAL) , If NORMAL
    then only you are printing the buffer and calling the function again.

    In the "receivePacket" function on select timeout or recvfrom failure(s) explicity update the "receivedPacket.flags" to otherthen NORMAL so that you are while loop will break.

查看更多
登录 后发表回答