#### spezielle Anpassung von _analyse.R zur Erstellung von PDF-Plots für die Masterarbeit: # Programmhinweis: cat("\n-----\nArgumente:\n\t(i) Indexplot\n\t(d) Densityplot\n\t(h) Histogram\n\t(v) Variation\n\t(p) Phasenplot\n\t(0.1) Y-Skala\n\nz.B. Rscript --vanilla _analyse.R -idp0.01\n-----\n\n") # Kommandozeilenargumente verarbeiten: arg <- commandArgs(TRUE)[1] if(is.na(arg) || !grepl("[idhvp]+", arg)){ arg <- "idhvp" # falls keines oder ungültig, generiere alle Plots! } # Libs laden (bei Fehlern, _install.R ausführen!): options(warn=-1) # Versions-Warnungen unterdrücken library(splines, quietly=TRUE) library(car, quietly=TRUE) library(stats, quietly=TRUE) library(graphics, quietly=TRUE) library(knitr, quietly=TRUE) library(markdown, quietly=TRUE) library(Rcmdr, quietly=TRUE) library(Hmisc, quietly=TRUE, warn.conflicts=FALSE) # für Lag(IPT, shift=1), erzeugt Warnung beim Laden... ### zusätzliche Schriftarten installieren library(extrafont) library(fontcm) loadfonts() # aktuelles Verzeichnis Übernehmen (fürs Skript, sonst ggf. manuell!): path <- paste(getwd(),"/", sep="") # paste(...) fügt ein "/" an setwd(path) # Schleife über alle CSV-Dateien: i <- 1 files <- list.files(pattern = "\\.csv$") # Workaround für auch mit ohne Endung: c(list.files(pattern = "\\.csv$"), list.files(pattern = "^([^.]+)$")) # Checken, ob Dateien gefunden wurden if(is.na(files[1])){ stop("Keine CSV-Dateien gefunden!\n") } cat("\nGefundene Dateien:\n") print(files) for (i in 1:length(files)){ cat(paste("\n","Bearbeite: ",i,"\n")) # Ausgabe der gerade bearbeiteten Datei # Einlesen und Prüfen/Korrigieren der CSV-Datei # csv-Datei einlesen: Datenmatrix <- read.csv(files[i]) # Format Überprüfen (Spaltennamen!): if(is.na(grep('^No.$|^Packet$', names(Datenmatrix))[1]) || is.na(grep('^Time', names(Datenmatrix))[1])){ stop("Format der CSV-Datei nicht korrekt!!! Erwarte: No.* | Time* | Source | Destination | Protocol | Length | IP-ID** | IPT** | Sequence*** (*notwendig, **sinnvoll, ***optional)") } # Spaltennamen ggf. korrigieren auf "No.", "IP-ID" und "IPT": names(Datenmatrix) <- sub('^IP.ID$', "IP-ID", names(Datenmatrix)) # nötig, da "-" beim Einlesen als "." interpretiert wird if(is.null(Datenmatrix$"No.") || is.null(Datenmatrix$"IP-ID") || is.null(Datenmatrix$"IPT")){ # falls eine Spalte nicht vorhanden print("Anpassung: Spaltennamen werden korrigiert...") # Ersetzen von möglichen Spaltennamen mithilfe von Regex-Ausdrücken names(Datenmatrix) <- sub('^Packet.*$', "No.", names(Datenmatrix)) # Packet* -> No. names(Datenmatrix) <- sub('^.*Ident.*$|^.*ID.*$', "IP-ID", names(Datenmatrix)) # *Ident* bzw. *ID* -> IP-ID names(Datenmatrix) <- sub('^.*IPT.*$|^.*Inter.*Packet.*$|^.*Delay.*$|^.*Delta.*$', "IPT", names(Datenmatrix)) # *IPT*, *Inter*Packet*, *Delay* oder *Delta* -> IPT # Übernahme der Änderungen write.table(Datenmatrix, files[i], sep=",", col.names=TRUE, row.names=FALSE, quote=TRUE, na="") } # Daten nach Wireshark-No. sortieren Datenmatrix <- Datenmatrix[order(Datenmatrix$No.),] # Wichtig für korrekte Berechnungen mit ursprünglicher Paketreihenfolge # falls IPT nicht vorhanden, Berechnung mittels Wireshark-Timestamp versuchen: if(is.na(grep('IPT|Inter.Packet|Delay|Delta', names(Datenmatrix))[1])){ print("Anpassung: Inter-Packet Time wird aus Time-Stamp berechnet...") # Berechnung der IPT mithilfe der Time*-Spalte Column <- grep('^Time', names(Datenmatrix))[1] Time <- as.numeric(sub(",", ".",Datenmatrix[[Column]])) # Zeit als Num mit Anpassung des Dezimalseperators (, -> .) IPT <- c(0,diff(Time)) # erster Wert und anschließen auf Differenz beruhende Berechnung -> 0, 2-1, 3-2, 4-3, ... # Übernahme der Änderungen Datenmatrix <- cbind(Datenmatrix,IPT) write.table(Datenmatrix, files[i], sep=",", col.names=TRUE, row.names=FALSE, quote=TRUE, na="") } # Bearbeitung der IP-ID-Informationen # falls vorhanden, IP-ID extrahieren: if(!is.null(Datenmatrix$"IP-ID") && !is.na(Datenmatrix$"IP-ID")){ print("Hinweis: Werte IP-ID aus (Retry/Error)...") # ID-Wert aufbereiten: ID <- sub(",", ".",Datenmatrix$"IP-ID") # ID als String mit Anpassung des Dezimalseperators (, -> .) if(!is.na(grep('^0x', ID)[1])){ print("Anpassung: Wandle IP-ID in Zahlenwert um...") # Umwandlung des Hex-Strings ID <- as.numeric(gsub("\\s.*", "", ID)) # entferne evtl. Anhänge und wandle Hex in Int um ("0x0011 (17)" -> 17) # Überlauf der Hex-ID behandeln (0xffff+1->0x0000) cnt <- 1 valold <- ID[1] overfows <- 0 for(val in ID){ # elementenweise Prüfung des ID-Vektors # Überlauferkennung, ID-Bereich bis 0x7fff (32767) oder 0xffff (65535)?! if(val<32767 && valold>32767){ # robuster bei Sequenzfehlern als if(ID==0 && IDalt==65535) print("Hinweis: Überlauf in der IP-ID gefunden...") overfows <- overfows+1 } # Überlaufbehandlung if(overfows>0){ ID[cnt] <- val+(overfows*65536) # Korrektur des ID-Vektors (0+65536 --> 65535+1) } valold <- val cnt <- cnt+1 } # Übernahme der Änderungen Datenmatrix$"IP-ID" <- ID write.table(Datenmatrix, files[i], sep=",", col.names=TRUE, row.names=FALSE, quote=TRUE, na="") } # falls ebenfalls vorhanden, Retry-Spalte einlesen (Retransmissionen!): if(!is.null(Datenmatrix$Retry) && !is.na(Datenmatrix$Retry)){ Retry <- as.logical(Datenmatrix$Retry) # Retry als Bool } else { # sonst aus ID-Sequenz erstellen: print("Anpassung: Erkenne Retransmissionen...") # ID-Duplikatssuche Datenmatrix <- Datenmatrix[order(Datenmatrix$"IP-ID"),] # Sortierung Ändern, da sonst nicht alle Retransmissionen erkannt werden (1,2,1,3,... -> 1,1,2,3,...) Retry <- duplicated(Datenmatrix$"IP-ID") # Wiederholungen = Retransmission Datenmatrix <- Datenmatrix[order(Datenmatrix$No.),] # Sortierung wieder rückgängig machen # Übernahme der Änderungen Datenmatrix <- cbind(Datenmatrix,Retry) write.table(Datenmatrix, files[i], sep=",", col.names=TRUE, row.names=FALSE, quote=TRUE, na="") } # falls vorhanden, Error-Spalte einlesen: if(!is.null(Datenmatrix$Error) && !is.na(Datenmatrix$Error)){ Error <- as.logical(Datenmatrix$Error) # Error als Bool } else { # sonst "leere" Spalte anfügen: Error <- FALSE # da bisher keine Fehler behandelt wurden Datenmatrix <- cbind(Datenmatrix,Error) } # falls bereits vorhanden, Sequence-Spalte einlesen: if(!is.null(Datenmatrix$Sequence) && !is.na(Datenmatrix$Sequence)){ Sequence <- as.numeric(sub(",", ".",Datenmatrix$Sequence)) # ID als Num mit Anpassung des Dezimalseperators (, -> .) } else { # sonst aus Sequenz erstellen und Fehler behandeln: print("Anpassung: Erstelle Paketsequenz...") # Normierung der IP-ID auf eine UDP-Paket-Sequenz-Nummer Sequence <- Datenmatrix$"IP-ID" - Datenmatrix$"IP-ID"[1] + 1 # Sequenz = 1,2,3,5,6,9,... Datenmatrix <- cbind(Datenmatrix,Sequence) # Kombination mit einer sequenzfehlerfreien Korrekturmatrix Korrekturmatrix <- data.frame(Sequence = seq(max(Sequence))) # Korrektur = 1,2,3,4,5,6,7,8,9,... Datenmatrix <- merge(Korrekturmatrix,Datenmatrix,all.x=TRUE) # IPT- und Fehler-Spalte ergänzen Datenmatrix$IPT[is.na(Datenmatrix$IPT)] <- -1 # IPT(Fehler) = -1 Datenmatrix$Error[is.na(Datenmatrix$Error)] <- TRUE # Fehler = TRUE # Übernahme der Änderungen write.table(Datenmatrix, files[i], sep=",", col.names=TRUE, row.names=FALSE, quote=TRUE, na="") } } else { print("Warnung: Keine IP-ID vorhanden!") Datenmatrix$"IP-ID" <- NULL Datenmatrix$Retry <- FALSE Datenmatrix$Error <- FALSE } ### Datenauswertung in PDF-Dateien # falls IPT nicht NULL, Auswertung beginnen: if(!is.null(Datenmatrix$IPT) && !is.na(Datenmatrix$IPT)){ # Daten nach erstellter Sequenz oder Wireshark-No. sortieren if(!is.null(Datenmatrix$Sequence)){ Datenmatrix <- Datenmatrix[order(Datenmatrix$Sequence),] # Wichtig zur Darstellung in Sequenzreihenfolge (mit Retransmissionen/Fehlern!) } else { Datenmatrix <- Datenmatrix[order(Datenmatrix$No.),] # Wichtig zur Darstellung in Wireshark-Reihenfolge } # Variablen zum einfacheren Verständnis des Programmcodes verwenden IPT <- as.numeric(sub(",", ".",Datenmatrix$IPT)) Error <- as.logical(Datenmatrix$Error) Retry <- as.logical(Datenmatrix$Retry) # IPDs für Analyse aufbereiten: IPT[IPT==-1] <- NA # Sequenzfehler verwerfen; -1(=Fehler) -> NA cnt <- 1 # Retry-IPTs aufbereiten; Retry-IPDs werden aufsummiert for(val in Retry){ # für alle Wiederholten Pakete if(isTRUE(val)){ IPT[cnt] <- IPT[cnt] + IPT[cnt-1] # die Zeiten aufsummieren } cnt <- cnt+1 } IPT <- na.omit(IPT) # NA -> / , wichtig für z.B. Density-Plot # statistische Informationen gewinnen und aufbereiten: InfosStat <- paste(names(summary(IPT)),summary(IPT),sep=" = ") # zusätzliche Sequenz-Informationen gewinnen und aufbereiten: InfosSeq <- paste(nrow(Datenmatrix),"Pakete") RetrySum <- sum(Retry, na.rm=TRUE) ErrorSum <- sum(Error, na.rm=TRUE) if(RetrySum > 0){ # falls Retrys, dann diese mit angeben InfosSeq <- paste(InfosSeq,paste("\nmit",RetrySum,"Retrys")) } if(ErrorSum > 0){ # falls Errors, dann diese mit angeben InfosSeq <- paste(InfosSeq,paste("\nmit",ErrorSum,"Fehlern")) } ### Grenzwert für PDFs ggf. anpassen!!! #ymax <- max(IPT, na.rm=TRUE) # fester oder dynamischer Grenzwert für die Plots: if(grepl("[[:digit:]]", arg)){ # Y-Skala aus Nutzereingabe: Grenze <- as.numeric(gsub("[[:alpha:]]", "", arg)) IPT <- IPT[IPT 0 IPT1[IPT1==0] <- NA # 0 -> NA IPT1[1] <- 0 # erster Wert zu 0 erzwingen (sonst NA -> Darstellung im Diagram ändert sich) IPT2 <- IPT*as.numeric(Retry) # !Retransmissionen -> 0 IPT2[IPT2==0] <- NA # 0 -> NA ### Anpassungen der Punktgröße und Farbe für PDFs: plot(IPT1, type='p', pch=4, cex=0.5, xlab="Paketnummer", ylab="IPT [s]", col="mediumblue", ylim=c(0, ymax)) # IPT1: normale Übertragungen points(IPT2, pch=1, cex=0.5, col="forestgreen") # IPT2: Retransmisionen # Zeichnen des ErrorPlot für die Sequenzfehler: ErrorPlot <- as.numeric(Error) ErrorPlot[ErrorPlot==0] <- NA # 0 -> NA ErrorPlot[ErrorPlot==1] <- 0 # 1 -> 0 points(ErrorPlot, pch=15, cex=0.5, col="firebrick") # ErrorPlot: Sequenzfehler # Aufbereitung des Graphen title(main=paste("Messung:",files[i])) # Titel legend(InfosStat, x="bottomright", bty="n") # statistische Infos legend(InfosSeq, x="topright", bty="n") # Paketinformationen (Anz., Wdh., Fehler) grid() # Liniengitter einzeichnen dev.off() # Datei schließen ### Schriftart in PDF einbetten: embed_fonts(filename, outfile=filename) } if(grepl("d", arg)){ # Density-Plot in *_density.pdf speichern: filename <- paste(path,unlist(strsplit(files[i], split=".csv", fixed=TRUE))[1],"_density",".pdf", sep="") print(paste("Erstelle:",filename)) ### Schriftart und Auflösung angepasst! pdf(filename, family="CM Roman", width=9, height=6) #png(filename, width=1920, height=1440, res=140) densityPlot(IPT, kernel="gaussian", xlab="IPT [s]", ylab="Dichte") #, ylim=c(0,100000)) title(main=paste("Messung:",files[i])) legend(InfosStat, x="topright", bty="n") grid() dev.off() ### Schrift in PDF einbetten: embed_fonts(filename, outfile=filename) } if(grepl("h", arg)){ # Histogram in *_histogram.pdf speichern: filename <- paste(path,unlist(strsplit(files[i], split=".csv", fixed=TRUE))[1],"_histogram",".pdf", sep="") print(paste("Erstelle:",filename)) ### Schriftart und Auflösung angepasst! pdf(filename, family="CM Roman", width=9, height=6) #png(filename, width=1920, height=1440, res=140) Hist(IPT, scale="frequency", breaks="Scott", xlab="IPT [s]", ylab="Häufigkeit", col="darkgray"))#, ylim=c(0,300)) # breaks=n/"Sturges"/"Scott"/"Freedman-Diaconis", vgl. ?nclass.Sturges # title(main=paste("Messung:",files[i])) grid() dev.off() ### Schriftart in PDF einbetten: embed_fonts(filename, outfile=filename) } if(grepl("v", arg)){ # IPT-Variation ("Jitter") berechnen: Variation <- diff(IPT) # Index-Plot der Variation in *-var.pdf speichern: filename <- paste(path,unlist(strsplit(files[i], split=".csv", fixed=TRUE))[1],"_variation",".pdf", sep="") print(paste("Erstelle:",filename)) ### Schriftart und Auflösung angepasst! pdf(filename, family="CM Roman", width=9, height=6) #png(filename, width=1920, height=1440, res=140) #plot(Variation, type='h', xlab="Paketnummer", ylab="Variation", col="darkblue") # Linien plot(Variation, type='p', pch=4, xlab="Paketnummer", ylab="Variation", col="darkblue") # Punkte title(main=paste("Verteilung der Variation aus\n",files[i])) grid() dev.off() ### Schriftart in PDF einbetten: embed_fonts(filename, outfile=filename) # Density-Plot der Variation in *-var_density.pdf speichern: ### Schriftart und Auflösung angepasst! pdf(filename, family="CM Roman", width=9, height=6) #png(paste(path,unlist(strsplit(files[i], split=".csv", fixed=TRUE))[1],"_variation_density",".pdf", sep=""), width=1024, height=768) densityPlot(Variation, kernel="gaussian", xlab="Variation", ylab="Dichte") title(main=paste("Messung:",files[i])) legend(InfosStat, x="topright", bty="n") grid() dev.off() ### Schriftart in PDF einbetten: embed_fonts(filename, outfile=filename) } if(grepl("p", arg)){ # Phasendiagramm in *_phase.pdf speichern: filename <- paste(path,unlist(strsplit(files[i], split=".csv", fixed=TRUE))[1],"_phase",".pdf", sep="") print(paste("Erstelle:",filename)) ### Schriftart und Auflösung angepasst! pdf(filename, family="CM Roman", width=9, height=6) #png(filename, width=1920, height=1440, res=140) plot(IPT, Lag(IPT, shift=1), type='p', pch=4, xlab="IPT(n)", ylab="IPT(n+1)", col="darkblue") title(main=paste("Messung:",files[i])) abline(0,1) grid() dev.off() ### Schriftart in PDF einbetten: embed_fonts(filename, outfile=filename) } } else { print("Fehler: Keine IPT vorhanden!") } }