因使用 alarm(); 而陷入超时循环



我正在尝试实现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("%dn", 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状态。

修复了它:

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

最新更新