sockets 通信 ソケット上のデータを再読み込みする



ソケット通信 c言語 サンプルプログラム (1)

私はシンプルなサーバー/クライアントのUDPソケットプログラムを作成しており、問題が発生しました。

問題は、recvfrom()関数が最後に送信されたデータを再読み込みすることです。

したがって、クライアントからサーバに2つのパケットを送信すると、recvfrom()は最初のパケットを読み込み、そのデータを出力します。その後、2番目のパケットは何度も何度も何度も読み込まれます。

私が理解しているように、成功した読み取り操作が実行されると、パケットはソケットから取り除かれるべきですが、それは起こっていないようです。

私は、クライアントがデータを送信するたびに書き出されるコンソール出力があるので、クライアントがデータを再送していないという事実を知っています。

送信者のための機能は次のとおりです

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

これは、このループで呼び出され、与えられた値に対して2回実行されます。

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. 失敗の場合(つまり、recvfromまたはselectがタイムアウトしたときに戻った場合)、初期化されていない "buffer"を返しています。そのため、コンテンツは予期したデータになる可能性がありますが、動作は未定義です。 したがって、recvfromを呼び出す前に、最初に0(memset(&buffer、0、sizeof(struct packet)))に初期化する方が良いです

  2. whileループでは、(receivedPacket.flags == NORMAL)、NORMAL
    あなただけがバッファを印刷して、関数を再度呼び出しています。

    select timeoutまたはrecvfromのエラーで "receivePacket"関数で明示的に "receivedPacket.flags"をNORMALに更新し、whileループが中断するようにします。





recvfrom