使用alarm()进入超时循环;

时间:2017-03-27 01:52:03

标签: c++ udp alarm recvfrom go-back-n

我尝试实施GoBackN协议,当服务器丢弃数据包时,我的警报会在发送所有先前发送的数据包之前等待2秒。

警报工作并等待2秒,但是在第一次超时后,我使用的状态机陷入循环并继续超时。我想这可能是因为errno没有重置,但我不确定。

#define TIMEOUT_SECS    2
#define MAXTRIES    10
int base = 0;
int windowSize = 7;
int sendFlag = 1;
int tries = 0;

int numPackets = 0;
packet *packetArray[30];

void addPacket(packet *p)
{
    for (int i = 0; i < 30; i++)
    {
        if (packetArray[i])
        {
            continue;
        }
        else
        {
            packetArray[i] = p;
            numPackets++;
            break;
        }
    }
}

void
CatchAlarm(int ignored)    /* Handler for SIGALRM */
{
  tries += 1;
  errno = 0;
}

void
DieWithError()
{
    printf("error");
  exit (1);
}

int
max(int a, int b)
{
  if (b > a)
    return b;
  return a;
}

int
min(int a, int b)
{
  if(b>a)
    return a;
  return b;
}

typedef enum
{
    wait,
    sendData,
    timeout,
    receiveData
} e_state;


int main(int argumentCount, char *argumentVariables[])
{

    //Grabbing all input information.
    struct hostent *emulatorName;
    emulatorName = gethostbyname(argumentVariables[1]);
    int receiveFromEmulator = atoi(argumentVariables[3]);
    int sendToEmulator = atoi(argumentVariables[2]);

    //Setting up UDP socket for receiving from emulator.
    int receiveSocket = 0;
    receiveSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

    //UDP socket configuration.
    struct sockaddr_in receiveSocketStruct;
    bzero((char *) &receiveSocketStruct, sizeof(receiveSocketStruct));
    receiveSocketStruct.sin_family = AF_INET;
    receiveSocketStruct.sin_port = htons(receiveFromEmulator);
    receiveSocketStruct.sin_addr.s_addr = INADDR_ANY;
    socklen_t receiveSocketLen = sizeof(receiveSocketStruct);

    //Binding UDP socket so client can locate emulator.
    bind(receiveSocket, (struct sockaddr *)&receiveSocketStruct, sizeof(receiveSocketStruct));

    //Setting up UDP socket for sending to emulator.
    int sendSocket = 0;
    sendSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

    //UDP socket configuration.
    struct sockaddr_in sendSocketStruct;
    bzero((char *) &sendSocketStruct, sizeof(sendSocketStruct));
    sendSocketStruct.sin_family = AF_INET;
    sendSocketStruct.sin_port = htons(sendToEmulator);
    sendSocketStruct.sin_addr.s_addr = INADDR_ANY;
    socklen_t sendSocketLen = sizeof(sendSocketStruct);

    char buffer[1024];

    std::ifstream infile (argumentVariables[4], std::ifstream::binary);
    infile.seekg (0, infile.end);
    int lengthOfFile = infile.tellg();
    infile.seekg (0, infile.beg);

    int totalPackets = 0;
    int nextSeqNum = 0;
    while(1)
    {
        if (lengthOfFile > 30)
        {
            bzero(buffer, 1024);
            char * data = new char[1024];
            infile.read(buffer, 30);
            strncpy(data, buffer, 1024);
            lengthOfFile -= 30;
            if (nextSeqNum > 7)
            {
                nextSeqNum = 0;
            }
            addPacket(new packet(1, nextSeqNum, strlen(data), data));
            totalPackets++;
            nextSeqNum++;
        }
        else
        {
            bzero(buffer, 1024);
            char * data = new char[1024];
            infile.read(buffer, 30);
            strncpy(data, buffer, 1024);
            if (nextSeqNum > 7)
            {
                nextSeqNum = 0;
            }
            addPacket(new packet(1, nextSeqNum, strlen(data), data));
            totalPackets++;
            nextSeqNum++;
            addPacket(new packet(3, nextSeqNum, 0, NULL));
            totalPackets++;
            break;
        }
    }

    infile.close();

    nextSeqNum = 0;
    int packetsReceived;
    int sentPackets;
    int receive = 0;
    char receivePayload[1024];
    char sendPayload[1024];

    struct sigaction myAction;    /* For setting signal handler */
    myAction.sa_handler = CatchAlarm;
    if (sigfillset (&myAction.sa_mask) < 0) /* block everything in handler */
        DieWithError ();
    myAction.sa_flags = 0;
    if (sigaction (SIGALRM, &myAction, 0) < 0)
        DieWithError ();

    e_state currentState = wait;
    e_state previousState = wait;

    while(1)
    {
        if (currentState == wait)
        {
            if (sendFlag == 1)
            {   
                previousState = currentState;
                currentState = sendData;
            }
            else
            {
                previousState = currentState;
                currentState = receiveData;
            }
        }
        else if (currentState == sendData)
        {
            if ((nextSeqNum < base + windowSize) && (nextSeqNum < totalPackets - 1))
            {
                //send packet with seqnum.
                int sendPacket = 0;
                bzero(sendPayload, 1024);
                packet * sendpckt = packetArray[nextSeqNum];
                sendpckt->serialize(sendPayload);
                sendpckt->printContents();
                sendPacket = sendto(sendSocket, sendPayload, sizeof(sendPayload), 0, (struct sockaddr *)&sendSocketStruct, sendSocketLen);

                if (base == nextSeqNum)
                {
                    alarm(0);
                    alarm(TIMEOUT_SECS);
                }
                nextSeqNum++;
            }
            else
            {
                sendFlag = 0;
                previousState = currentState;
                currentState = wait;
            }
        }
        else if (currentState == timeout)
        {
            alarm(0);
            alarm(TIMEOUT_SECS);

            for(int counter = base; counter < nextSeqNum; counter++)
            {   
                int sendPacket = 0;
                bzero(sendPayload, 1024);
                packet * sendpckt = packetArray[counter];
                sendpckt->serialize(sendPayload);
                sendpckt->printContents();
                sendPacket = sendto(sendSocket, sendPayload, sizeof(sendPayload), 0, (struct sockaddr *)&sendSocketStruct, sendSocketLen);
            }

            sendFlag = 0;
            previousState = currentState;
            currentState = wait;
        }
        else if (currentState == receiveData)
        {
            bzero(receivePayload, 1024);
            receive = (recvfrom(receiveSocket, receivePayload, sizeof(receivePayload), 0, (struct sockaddr *)&receiveSocketStruct, &receiveSocketLen));
            if (errno == EINTR)
            {
                printf("timeout");
                if (tries > MAXTRIES)
                {
                    alarm(0);
                    break;
                    printf("recvfrom() failed.");
                }

                previousState = currentState;
                currentState = timeout;
            }
            else
            {
                char buffer[1024];
                bzero(buffer, 1024);
                int receivePacketType;
                int receivePacketSeqNum;

                packet recvpckt(0, 0, 0, (char*)buffer);
                recvpckt.deserialize((char*)receivePayload);

                receivePacketSeqNum = recvpckt.getSeqNum();
                receivePacketType = recvpckt.getType();
                recvpckt.printContents();

                if (receivePacketType == 2)
                {
                    break;
                }

                base = receivePacketSeqNum + 1;
                printf("%d\n", base);

                if (base == nextSeqNum)
                {
                    alarm(0);
                }
                else
                {
                    alarm(0);
                    alarm(TIMEOUT_SECS);
                }

                if (nextSeqNum == totalPackets - 1)
                {
                    nextSeqNum++;
                    int sendPacket = 0;
                    bzero(sendPayload, 1024);
                    packet * sendpckt = packetArray[nextSeqNum - 1];
                    sendpckt->serialize(sendPayload);
                    sendpckt->printContents();
                    sendPacket = sendto(sendSocket, sendPayload, sizeof(sendPayload), 0, (struct sockaddr *)&sendSocketStruct, sendSocketLen);
                }

                if (base <= totalPackets)
                {  
                    sendFlag = 1;
                    previousState = currentState;
                    currentState = wait;
                }
                else
                {
                    continue;
                }
            }
        }
        else
        {
            break;
        }
    }

    //Close shop.
    close(receiveSocket);
    close(sendSocket);

    return 0;
}

我怀疑循环开始的位置是receiveData状态。

1 个答案:

答案 0 :(得分:0)

修正了它:

else if (currentState == receiveData)
        {
            receive = 0;
            bzero(receivePayload, 1024);
            receive = (recvfrom(receiveSocket, receivePayload, sizeof(receivePayload), 0, (struct sockaddr *)&receiveSocketStruct, &receiveSocketLen));
            if (receive < 0)
            {
                printf("timeout");
                if (tries > MAXTRIES)
                {
                    alarm(0);
                    break;
                    printf("recvfrom() failed.");
                }

            previousState = currentState;
            currentState = timeout;
        }