Застрял в таймауте от использования 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("%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 государство.

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

Другие решения

Других решений пока нет …