recvfrom re-reading data on socket

女生的网名这么多〃 提交于 2019-12-11 18:19:56

问题


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:


  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.



来源:https://stackoverflow.com/questions/22487120/recvfrom-re-reading-data-on-socket

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!