📄 sim.c
字号:
/* Simulator for the protocols in chapter 3 of * "Computer Networks, 3rd ed. by Andrew S. Tanenbaum. */#include <sys/types.h>#include <sys/stat.h>#include <stdlib.h>#include <string.h>#include <signal.h>#include <unistd.h>#include <stdio.h>#include "common.h"#define DEADLOCK (3 * timeout_interval) /* defines what a deadlock is */#define MAX_PROTOCOL 6 /* highest protocol being simulated */#define MANY 256 /* big enough to clear pipe at the end */bigint tick = 0; /* the current time, measured in events */bigint last_tick; /* when to stop the simulation */int exited[2]; /* set if exited (for each worker) */int hanging[2]; /* # times a process has done nothing */struct sigaction act, oact;/* Prototypes. */void main(int argc, char *argv[]);int parse_args(int argc, char *argv[]);void set_up_pipes(void);void fork_off_workers(void);void terminate(char *s);void sender2(void);void receiver2(void);void sender3(void);void receiver3(void);void protocol4(void);void protocol5(void);void protocol6(void);void main(int argc, char *argv[]){/* The simulator has three processes: main, M0, and M1, all of which run * independently. Set them all up first. Once set up, main maintains the * clock (tick), and picks a process to run. Then it writes a 32-bit word * to that process to tell it to run. The process sends back an answer * when it is done. Main then picks another process, and the cycle repeats. */ int process = 0; /* whose turn is it */ int rfd, wfd; /* file descriptor for talking to workers */ bigint word; /* message from worker */ act.sa_handler = SIG_IGN; setvbuf(stdout, (char *) 0, _IONBF, (size_t) 0); /* disable buffering*/ if (parse_args(argc, argv) < 0) exit(1); /* check args; store in mem */ set_up_pipes(); /* create five pipes */ fork_off_workers(); /* fork off the worker processes */ /* Main simulation loop. */ while (tick <last_tick) { process = rand() & 1; /* pick process to run: 0 or 1 */ tick = tick + DELTA; rfd = (process == 0 ? r4 : r6); if (read(rfd, &word, TICK_SIZE) != TICK_SIZE) terminate(""); if (word == OK) hanging[process] = 0; if (word == NOTHING) hanging[process] += DELTA; if (hanging[0] >= DEADLOCK && hanging[1] >= DEADLOCK) terminate("A deadlock has been detected"); /* Write the time to the selected process to tell it to run. */ wfd = (process == 0 ? w3 : w5); if (write(wfd, &tick, TICK_SIZE) != TICK_SIZE) terminate("Main could not write to worker"); } /* Simulation run has finished. */ terminate("End of simulation");}int parse_args(int argc, char *argv[]){/* Inspect args on the command line and save them. */ if (argc != 7) { printf("Usage: sim protocol events timeout loss cksum debug\n"); return(-1); } protocol = atoi(argv[1]); if (protocol < 2 || protocol > MAX_PROTOCOL) { printf("Protocol %d is not valid.\n", protocol); return(-1); } /* Each event uses DELTA ticks to make it possible for each timeout to * occur at a different tick. For example, with DELTA = 10, ticks will * occur at 0, 10, 20, etc. This makes it possible for a timeout in * protocol 5 to schedule multiple timeouts for the future, all at unique * times, e.g. 1070, 1071, 1072, 1073, etc. This property is needed to * make sure timers go off in the order they were set. As a consequence, * internally, the variable tick is bumped by DELTA on each event. Thus * asking for a simulation run of 1000 events will give 1000 events, but * they internally they will be called 0 to 10,000. */ last_tick = DELTA * atol(argv[2]); /* each event uses DELTA ticks */ if ((long) last_tick < 0) { printf("Number of simulation events must be positive\n"); return(-1); } /* Convert from external units to internal units so the user does not see * the internal units at all. */ timeout_interval = DELTA * atoi(argv[3]); if ((long)timeout_interval < 0 || (protocol > 2 && timeout_interval == 0) ){ printf("Timeout interval must be positive\n"); return(-1); } /* Packet loss takes place at the sender. Packets selected for being lost * are not put on the wire at all. Internally, pkt_loss and garbled are * from 0 to 990 so they can be compared to 10 bit random numbers. The * inaccuracy here is about 2.4% because 1000 != 1024. In effect, it is * not possible to say that all packets are lost. The most that can be * be lost is 990/1024. */ pkt_loss = atoi(argv[4]); /* 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(-1); } pkt_loss = 10 * pkt_loss; /* for our purposes, 1000 == 1024 */ /* This arg tells what fraction of arriving packets are garbled. Thus if * pkt_loss is 50 and garbled is 50, half of all packets (actually, * 500/1024 of all packets) will not be sent at all, and of the ones that * are sent, 500/1024 will arrive garbled. */ garbled = atoi(argv[5]); if (garbled < 0 || garbled > 99) { printf("Packet cksum rate must be between 0 and 99\n", garbled); return(-1); } garbled = 10 * garbled; /* for our purposes, 1000 == 1024 */ /* Turn tracing options on or off. The bits are defined in worker.c. */ debug_flags = atoi(argv[6]); if (debug_flags < 0) { printf("Debug flags may not be negative\n", debug_flags); return(-1); } printf("\n\nProtocol %d. Events: %u Parameters: %u %d %u\n", protocol, last_tick/DELTA, timeout_interval/DELTA, pkt_loss/10, garbled/10, debug_flags); return(0); /* no errors in command line parameters */}void set_up_pipes(void){/* Create six pipes so main, M0 and M1 can communicate pairwise. */ int fd[2]; pipe(fd); r1 = fd[0]; w1 = fd[1]; /* M0 to M1 for frames */ pipe(fd); r2 = fd[0]; w2 = fd[1]; /* M1 to M0 for frames */ pipe(fd); r3 = fd[0]; w3 = fd[1]; /* main to M0 for go-ahead */ pipe(fd); r4 = fd[0]; w4 = fd[1]; /* M0 to main to signal readiness */ pipe(fd); r5 = fd[0]; w5 = fd[1]; /* main to M1 for go-ahead */ pipe(fd); r6 = fd[0]; w6 = fd[1]; /* M1 to main to signal readiness */}void fork_off_workers(void){/* Fork off the two workers, M0 and M1. */ if (fork() != 0) { /* This is the Parent. It will become main, but first fork off M1. */ if (fork() != 0) { /* This is main. */ sigaction(SIGPIPE, &act, &oact); setvbuf(stdout, (char *)0, _IONBF, (size_t)0);/*don't buffer*/ close(r1); close(w1); close(r2); close(w2); close(r3); close(w4); close(r5); close(w6); return; } else { /* This is the code for M1. Run protocol. */ sigaction(SIGPIPE, &act, &oact); setvbuf(stdout, (char *)0, _IONBF, (size_t)0);/*don't buffer*/ close(w1); close(r2); close(r3); close(w3); close(r4); close(w4); close(w5); close(r6); id = 1; /* M1 gets id 1 */ mrfd = r5; /* fd for reading time from main */ mwfd = w6; /* fd for writing reply to main */ prfd = r1; /* fd for reading frames from worker 0 */ switch(protocol) { case 2: receiver2(); break; case 3: receiver3(); break; case 4: protocol4(); break; case 5: protocol5(); break; case 6: protocol6(); break; } terminate("Impossible. Protocol terminated"); } } else { /* This is the code for M0. Run protocol. */ sigaction(SIGPIPE, &act, &oact); setvbuf(stdout, (char *)0, _IONBF, (size_t)0);/*don't buffer*/ close(r1); close(w2); close(w3); close(r4); close(r5); close(w5); close(r6); id = 0; /* M0 gets id 0 */ mrfd = r3; /* fd for reading time from main */ mwfd = w4; /* fd for writing reply to main */ prfd = r2; /* fd for reading frames from worker 1 */ switch(protocol) { case 2: sender2(); break; case 3: sender3(); break; case 4: protocol4(); break; case 5: protocol5(); break; case 6: protocol6(); break; } terminate("Impossible. protocol terminated"); }}void terminate(char *s){/* End the simulation run by sending each worker a 32-bit zero command. */ int n, k1, k2, res1[MANY], res2[MANY], eff, acc, sent; for (n = 0; n < MANY; n++) {res1[n] = 0; res2[n] = 0;} write(w3, &zero, TICK_SIZE); write(w5, &zero, TICK_SIZE); sleep(2); /* Clean out the pipe. The zero word indicates start of statistics. */ n = read(r4, res1, MANY*sizeof(int)); k1 = 0; while (res1[k1] != 0) k1++; k1++; /* res1[k1] = accepted, res1[k1+1] = sent */ /* Clean out the other pipe and look for statistics. */ n = read(r6, res2, MANY*sizeof(int)); k2 = 0; while (res1[k2] != 0) k2++; k2++; /* res1[k2] = accepted, res1[k2+1] = sent */ if (strlen(s) > 0) { acc = res1[k1] + res2[k2]; sent = res1[k1+1] + res2[k2+1]; if (sent > 0) { eff = (100 * acc)/sent; printf("\nEfficiency (payloads accepted/data pkts sent) = %d%c\n", eff, '%'); } printf("%s. Time=%u\n",s, tick/DELTA); } exit(1); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -