📄 simulator.c
字号:
if (frct > 0) { /* How many frames can be read consecutively? */ top = (outp <= inp ? &queue[MAX_QUEUE] : outp);/* how far can we rd?*/ k = top - inp; /* number of frames that can be read consecutively */ if (k > frct) k = frct; /* how many frames to read from peer */ if (read(prfd, inp, k * FRAME_SIZE) != k * FRAME_SIZE) sim_error("Error reading frames from peer"); frct -= k; /* residual frames not yet read */ inp += k; if (inp == &queue[MAX_QUEUE]) inp = queue; nframes += k; /* If frct is still > 0, the queue has been filled to the upper * limit, but there is still space at the bottom. Continue reading * there. This mechanism makes queue a circular buffer. */ if (frct > 0) { if (read(prfd, queue, frct * FRAME_SIZE) != frct*FRAME_SIZE) sim_error("Error 2 reading frames from peer"); nframes += frct; inp = &queue[frct]; } }}int pick_event(void){/* Pick a random event that is now possible for the process. * Note that the order in which the tests is made is critical, as it gives * priority to some events over others. For example, for protocols 3 and 4 * frames will be delivered before a timeout will be caused. This is probably * a reasonable strategy, and more closely models how a real line works. */ if (check_ack_timer() > 0) return(ack_timeout); if (nframes > 0) return((int)frametype()); if (network_layer_status) return(network_layer_ready); if (check_timers() >= 0) return(timeout); /* timer went off */ return(NO_EVENT);}event_type frametype(void){/* This function is called after it has been decided that a frame_arrival * event will occur. The earliest frame is removed from queue[] and copied * to last_frame. This copying is needed to avoid messing up the simulation * in the event that the protocol does not actually read the incoming frame. * For example, in protocols 2 and 3, the senders do not call * from_physical_layer() to collect the incoming frame. If frametype() did * not remove incoming frames from queue[], they never would be removed. * Of course, one could change sender2() and sender3() to have them call * from_physical_layer(), but doing it this way is more robust. * * This function determines (stochastically) whether the arrived frame is good * or bad (contains a checksum error). */ int n, i; event_type event; /* Remove one frame from the queue. */ last_frame = *outp; /* copy the first frame in the queue */ outp++; if (outp == &queue[MAX_QUEUE]) outp = queue; nframes--; /* Generate frames with checksum errors at random. */ n = rand() & 01777; if (n < garbled) { /* Checksum error.*/ event = cksum_err; if (last_frame.kind == data) cksum_data_recd++; if (last_frame.kind == ack) cksum_acks_recd++; i = 0; } else { event = frame_arrival; if (last_frame.kind == data) good_data_recd++; if (last_frame.kind == ack) good_acks_recd++; i = 1; } if (debug_flags & RECEIVES) { printf("Tick %u. Proc %d got %s frame: ", tick/DELTA,id,badgood[i]); fr(&last_frame); } return(event);}void from_network_layer(packet *p){/* Fetch a packet from the network layer for transmission on the channel. */ p->data[0] = (next_net_pkt >> 24) & BYTE; p->data[1] = (next_net_pkt >> 16) & BYTE; p->data[2] = (next_net_pkt >> 8) & BYTE; p->data[3] = (next_net_pkt ) & BYTE; next_net_pkt++;}void to_network_layer(packet *p){/* Deliver information from an inbound frame to the network layer. A check is * made to see if the packet is in sequence. If it is not, the simulation * is terminated with a "protocol error" message. */ unsigned int num; num = pktnum(p); if (num != last_pkt_given + 1) { printf("Tick %u. Proc %d got protocol error. Packet delivered out of order.\n", tick/DELTA, id); printf("Expected payload %d but got payload %d\n",last_pkt_given+1,num); exit(0); } last_pkt_given = num; payloads_accepted++;} void from_physical_layer (frame *r){/* Copy the newly-arrived frame to the user. */ *r = last_frame;}void to_physical_layer(frame *s){/* Pass the frame to the physical layer for writing on pipe 1 or 2. * However, this is where bad packets are discarded: they never get written. */ int fd, got, k; /* The following statement is essential to later on determine the timed * out sequence number, e.g. in protocol 6. Keeping track of * this information is a bit tricky, since the call to start_timer() * does not tell what the sequence number is, just the buffer. The * simulator keeps track of sequence numbers using the array seqs[], * which records the sequence number of each data frame sent, so on a * timeout, knowing the buffer number makes it possible to determine * the sequence number. */ if (s->kind==data) seqs[s->seq % (nseqs/2)] = s->seq; if (s->kind == data) data_sent++; if (s->kind == ack) acks_sent++; if (retransmitting) data_retransmitted++; /* Bad transmissions (checksum errors) are simulated here. */ k = rand() & 01777; /* 0 <= k <= about 1000 (really 1023) */ if (k < pkt_loss) { /* simulate packet loss */ if (debug_flags & SENDS) { printf("Tick %u. Proc %d sent frame that got lost: ", tick/DELTA, id); fr(s); } if (s->kind == data) data_lost++; /* statistics gathering */ if (s->kind == ack) acks_lost++; /* ditto */ return; } if (s->kind == data) data_not_lost++; /* statistics gathering */ if (s->kind == ack) acks_not_lost++; /* ditto */ fd = (id == 0 ? w1 : w2); got = write(fd, s, FRAME_SIZE); if (got != FRAME_SIZE) print_statistics(); /* must be done */ if (debug_flags & SENDS) { printf("Tick %u. Proc %d sent frame: ", tick/DELTA, id); fr(s); }}void start_timer(seq_nr k){/* Start a timer for a data frame. */ ack_timer[k] = tick + timeout_interval + offset; offset++; recalc_timers(); /* figure out which timer is now lowest */}void stop_timer(seq_nr k){/* Stop a data frame timer. */ ack_timer[k] = 0; recalc_timers(); /* figure out which timer is now lowest */}void start_ack_timer(void){/* Start the auxiliary timer for sending separate acks. The length of the * auxiliary timer is arbitrarily set to half the main timer. This could * have been another simulation parameter, but that is unlikely to have * provided much extra insight. */ aux_timer = tick + timeout_interval/AUX; offset++;}void stop_ack_timer(void){/* Stop the ack timer. */ aux_timer = 0;}void enable_network_layer(void){/* Allow network_layer_ready events to occur. */ network_layer_status = 1;}void disable_network_layer(void){/* Prevent network_layer_ready events from occuring. */ network_layer_status = 0;}int check_timers(void){/* Check for possible timeout. If found, reset the timer. */ int i; /* See if a timeout event is even possible now. */ if (lowest_timer == 0 || tick < lowest_timer) return(-1); /* A timeout event is possible. Find the lowest timer. Note that it is * impossible for two frame timers to have the same value, so that when a * hit is found, it is the only possibility. The use of the offset variable * guarantees that each successive timer set gets a higher value than the * previous one. */ for (i = 0; i < NR_TIMERS; i++) { if (ack_timer[i] == lowest_timer) { ack_timer[i] = 0; /* turn the timer off */ recalc_timers(); /* find new lowest timer */ oldest_frame = seqs[i]; /* timed out sequence number */ return(i); } } printf("Impossible. check_timers failed at %d\n", lowest_timer); exit(1);}int check_ack_timer(){/* See if the ack timer has expired. */ if (aux_timer > 0 && tick >= aux_timer) { aux_timer = 0; return(1); } else { return(0); }}unsigned int pktnum(packet *p){/* Extract packet number from packet. */ unsigned int num, b0, b1, b2, b3; b0 = p->data[0] & BYTE; b1 = p->data[1] & BYTE; b2 = p->data[2] & BYTE; b3 = p->data[3] & BYTE; num = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; return(num);}void fr(frame *f){/* Print frame information for tracing. */ printf("type=%s seq=%d ack=%d payload=%d\n", tag[f->kind], f->seq, f->ack, pktnum(&f->info));}void recalc_timers(void){/* Find the lowest timer */ int i; bigint t = UINT_MAX; for (i = 0; i < NR_TIMERS; i++) { if (ack_timer[i] > 0 && ack_timer[i] < t) t = ack_timer[i]; } lowest_timer = t;}void print_statistics(void){/* Display statistics. */ int word[3]; sleep(1); printf("\nProcess %d:\n", id); printf("\tTotal data frames sent: %9d\n", data_sent); printf("\tData frames lost: %9d\n", data_lost); printf("\tData frames not lost: %9d\n", data_not_lost); printf("\tFrames retransmitted: %9d\n", data_retransmitted); printf("\tGood ack frames rec'd: %9d\n", good_acks_recd); printf("\tBad ack frames rec'd: %9d\n\n", cksum_acks_recd); printf("\tGood data frames rec'd: %9d\n", good_data_recd); printf("\tBad data frames rec'd: %9d\n", cksum_data_recd); printf("\tPayloads accepted: %9d\n", payloads_accepted); printf("\tTotal ack frames sent: %9d\n", acks_sent); printf("\tAck frames lost: %9d\n", acks_lost); printf("\tAck frames not lost: %9d\n", acks_not_lost); printf("\tTimeouts: %9d\n", timeouts); printf("\tAck timeouts: %9d\n", ack_timeouts); fflush(stdin); word[0] = 0; word[1] = payloads_accepted; word[2] = data_sent; write(mwfd, word, 3*sizeof(int)); /* tell main we are done printing */ sleep(1); exit(0);}void sim_error(char *s){/* A simulator error has occurred. */ int fd; printf("%s\n", s); fd = (id == 0 ? w4 : w6); write(fd, &zero, TICK_SIZE); exit(1);}int parse_first_five_parameters(int argc, char *argv[], long *event, int *timeout_interval, int *pkt_loss, int *garbled, int *debug_flags){/* Help function for protocol writers to parse first five command-line * parameters that the simulator needs. */ if (argc < 6) { printf("Need at least five command-line parameters.\n"); return(0); } *event = atol(argv[1]); if (*event < 0) { printf("Number of simulation events must be positive\n"); return(0); } *timeout_interval = atoi(argv[2]); if (*timeout_interval < 0){ printf("Timeout interval must be positive\n"); return(0); } *pkt_loss = atoi(argv[3]); /* percent of sends that chuck pkt out */ if (*pkt_loss < 0 || *pkt_loss > 99) { printf("Packet loss rate must be between 0 and 99\n"); return(0); } *garbled = atoi(argv[4]); if (*garbled < 0 || *garbled > 99) { printf("Packet cksum rate must be between 0 and 99\n"); return(0); } *debug_flags = atoi(argv[5]); if (*debug_flags < 0) { printf("Debug flags may not be negative\n"); return(0); } return(1);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -