From 33613a85afc4b1481367fbe92a17ee59c240250b Mon Sep 17 00:00:00 2001 From: Sven Eisenhauer Date: Fri, 10 Nov 2023 15:11:48 +0100 Subject: add new repo --- Bachelor/Verteilte Systeme/Praktikum1/Makefile | 14 + Bachelor/Verteilte Systeme/Praktikum1/README | 22 ++ Bachelor/Verteilte Systeme/Praktikum1/error.cpp | 331 ++++++++++++++++++++++ Bachelor/Verteilte Systeme/Praktikum1/inet.h | 19 ++ Bachelor/Verteilte Systeme/Praktikum1/tcpcli.cpp | 129 +++++++++ Bachelor/Verteilte Systeme/Praktikum1/tcpserv.cpp | 226 +++++++++++++++ Bachelor/Verteilte Systeme/Praktikum1/util.cpp | 86 ++++++ 7 files changed, 827 insertions(+) create mode 100644 Bachelor/Verteilte Systeme/Praktikum1/Makefile create mode 100644 Bachelor/Verteilte Systeme/Praktikum1/README create mode 100644 Bachelor/Verteilte Systeme/Praktikum1/error.cpp create mode 100644 Bachelor/Verteilte Systeme/Praktikum1/inet.h create mode 100644 Bachelor/Verteilte Systeme/Praktikum1/tcpcli.cpp create mode 100644 Bachelor/Verteilte Systeme/Praktikum1/tcpserv.cpp create mode 100644 Bachelor/Verteilte Systeme/Praktikum1/util.cpp (limited to 'Bachelor/Verteilte Systeme/Praktikum1') diff --git a/Bachelor/Verteilte Systeme/Praktikum1/Makefile b/Bachelor/Verteilte Systeme/Praktikum1/Makefile new file mode 100644 index 0000000..2e568e8 --- /dev/null +++ b/Bachelor/Verteilte Systeme/Praktikum1/Makefile @@ -0,0 +1,14 @@ +all: tcpserv tcpcli + +tcpserv: tcpserv.o + g++ tcpserv.o -o tcpserv +tcpcli: tcpcli.o + g++ tcpcli.o -o tcpcli + +tcpserv.o: + g++ -c -o tcpserv.o tcpserv.cpp +tcpcli.o: + g++ -c -o tcpcli.o tcpcli.cpp + +clean: + rm -f *.o tcpserv tcpcli diff --git a/Bachelor/Verteilte Systeme/Praktikum1/README b/Bachelor/Verteilte Systeme/Praktikum1/README new file mode 100644 index 0000000..74355c2 --- /dev/null +++ b/Bachelor/Verteilte Systeme/Praktikum1/README @@ -0,0 +1,22 @@ +1. Die Programme sind zu uebersetzen (auf Server und Client Rechner): + $ make tcpserv + g++ tcpserv.cpp -o tcpserv + $ + $ make tcpcli + g++ tcpcli.cpp -o tcpcli + $ + +2. Nun kann das Serverprogramm auf dem Server gestartet werden: + $ tcpserv $ + $ + +3. Auf jedem Clientrechner kann nun der Client gestartet werden. + $ tcpcli + Dies ist die erste Zeile + Dies ist die erste Zeile + 2. Nachricht + 2. Nachricht + Letzte Nachricht + Letzte Nachricht + ^D + $ diff --git a/Bachelor/Verteilte Systeme/Praktikum1/error.cpp b/Bachelor/Verteilte Systeme/Praktikum1/error.cpp new file mode 100644 index 0000000..5bf172d --- /dev/null +++ b/Bachelor/Verteilte Systeme/Praktikum1/error.cpp @@ -0,0 +1,331 @@ +/************************************************************************ + * Error handling routines. + * + * The functions in this file are independent of any application + * variables, and may be used with any C program. + * Either of the names CLIENT or SERVER may be defined when compiling + * this function. If neither are defined, we assume CLIENT. + */ + +//#include +#include +#include +#include + +#include +using namespace std; + +#ifdef CLIENT +#ifdef SERVER +cant define both CLIENT and SERVER +#endif +#endif + +#ifndef CLIENT +#ifndef SERVER +#define CLIENT 1 /* default to client */ + +#endif +#endif + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +char *pname = NULL; + +#ifdef CLIENT /* these all output to stderr */ + + /* ------------------- BEGIN CLIENT ------------------- */ + +/* + * Print the UNIX errno value. + */ + +void my_perror() +{ + //char *sys_err_str(); + char *str = strerror(errno); + cerr << str << endl; + //fprintf(stderr, " %s\n", sys_err_str()); +} +/* + * Print the UNIX errno value. + * We just append it to the end of the emesgstr[] array. + */ + + + +/* + * Fatal error. Print a message and terminate. + * Don't dump core and don't print the system's errno value. + * + * err_quit(str, arg1, arg2, ...) + * + * The string "str" must specify the conversion specification for any args. + */ + +/*VARARGS1*/ + +void err_quit(char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + if (pname != NULL) + cerr << pname; + fmt = va_arg(args, char *); + vfprintf(stderr, fmt, args); + fputc('\n', stderr); + va_end(args); + + exit(1); +} + +/* + * Fatal error related to a system call. Print a message and terminate. + * Don't dump core, but do print the system's errno value and its + * associated message. + * + * err_sys(str, arg1, arg2, ...) + * + * The string "str" must specify the conversion specification for any args. + */ + +/*VARARGS1*/ +void err_sys(char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + if (pname != NULL) { + cerr << "if (pname != NULL) {" << endl; + fprintf(stderr, "%s: ", pname); + + } + fmt = va_arg(args, char *); + + vfprintf(stderr, fmt, args); + va_end(args); + + my_perror(); + + exit(1); +} + +/* + * Recoverable error. Print a message, and return to caller. + * + * err_ret(str, arg1, arg2, ...) + * + * The string "str" must specify the conversion specification for any args. + */ + +/*VARARGS1*/ +void err_ret(char *fmt, ...) +{ + va_list args; + + + va_start(args, fmt); + if (pname != NULL) + fprintf(stderr, "%s: ", pname); + fmt = va_arg(args, char *); + vfprintf(stderr, fmt, args); + va_end(args); + + my_perror(); + + fflush(stdout); + fflush(stderr); + + return; +} + +/* + * Fatal error. Print a message, dump core (for debugging) and terminate. + * + * err_dump(str, arg1, arg2, ...) + * + * The string "str" must specify the conversion specification for any args. + */ + +/*VARARGS1*/ +void err_dump(char *fmt, ...) +{ + va_list args; + + + va_start(args, fmt); + if (pname != NULL) + fprintf(stderr, "%s: ", pname); + fmt = va_arg(args, char *); + vfprintf(stderr, fmt, args); + va_end(args); + + my_perror(); + + fflush(stdout); /* abort doesn't flush stdio buffers */ + fflush(stderr); + + abort(); /* dump core and terminate */ + exit(1); /* shouldn't get here */ +} + +#endif /* ------------------- END CLIENT ------------------- */ + /* ------------------- BEGIN SERVER ------------------- */ +#ifdef SERVER + +#ifdef BSD +/* + * Under BSD, these server routines use the syslog(3) facility. + * They don't append a newline, for example. + */ + +#include + +#else /* not BSD */ +/* + * There really ought to be a better way to handle server logging + * under System V. + */ + +#define syslog(a,b) cerr << "syslog: "<< (b) +#define openlog(a,b,c) cerr << (a) + +#endif /* BSD */ +/* + * Print the UNIX errno value. + * We just append it to the end of the emesgstr[] array. + */ + +char emesgstr[255] = {"test"}; /* used by all server routines */ +void my_perror() +{ + + // register int len; + //char *sys_err_str(); +// len = strlen(emesgstr); + cerr << emesgstr + << strerror(errno) + << endl; + //sprintf(emesgstr + len, " %s", sys_err_str()); +} + + + +/* + * Identify ourself, for syslog() messages. + * + * LOG_PID is an option that says prepend each message with our pid. + * LOG_CONS is an option that says write to console if unable to send + * the message to syslogd. + * LOG_DAEMON is our facility. + */ + +void err_init(char *ident) +{ + openlog(ident, (LOG_PID | LOG_CONS), LOG_DAEMON); +} + +/* + * Fatal error. Print a message and terminate. + * Don't print the system's errno value. + * + * err_quit(str, arg1, arg2, ...) + * + * The string "str" must specify the conversion specification for any args. + */ + +/*VARARGS1*/ +void err_quit(char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + fmt = va_arg(args, char *); + vsprintf(emesgstr, fmt, args); + va_end(args); + + syslog(LOG_ERR, emesgstr); + + exit(1); +} + +/* + * Fatal error related to a system call. Print a message and terminate. + * Don't dump core, but do print the system's errno value and its + * associated message. + * + * err_sys(str, arg1, arg2, ...) + * + * The string "str" must specify the conversion specification for any args. + */ + +/*VARARGS1*/ +void err_sys(char *fmt, ...) + +{ + cerr << "err_sys: " << fmt << endl; + va_list args; + va_start(args, fmt); + fmt = va_arg(args, char *); + vsprintf(emesgstr, fmt, args); + va_end(args); + + my_perror(); + syslog(LOG_ERR, emesgstr); + + exit(1); +} + +/* + * Recoverable error. Print a message, and return to caller. + * + * err_ret(str, arg1, arg2, ...) + * + * The string "str" must specify the conversion specification for any args. + */ + +/*VARARGS1*/ +void err_ret(char *fmt, ...) + +{ + va_list args; + + va_start(args, fmt); + fmt = va_arg(args, char *); + vsprintf(emesgstr, fmt, args); + va_end(args); + + my_perror(); + syslog(LOG_ERR, emesgstr); + + return; +} + +/* + * Fatal error. Print a message, dump core (for debugging) and terminate. + * + * err_dump(str, arg1, arg2, ...) + * + * The string "str" must specify the conversion specification for any args. + */ + +/*VARARGS1*/ +void err_dump(char *fmt, ...) + +{ + va_list args; + va_start(args,fmt); + fmt = va_arg(args, char *); + vsprintf(emesgstr, fmt, args); + va_end(args); + + my_perror(); + syslog(LOG_ERR, emesgstr); + + abort(); /* dump core and terminate */ + exit(1); /* shouldn't get here */ +} + + +#endif /* ------------------- SERVER ------------------- */ diff --git a/Bachelor/Verteilte Systeme/Praktikum1/inet.h b/Bachelor/Verteilte Systeme/Praktikum1/inet.h new file mode 100644 index 0000000..6af7e71 --- /dev/null +++ b/Bachelor/Verteilte Systeme/Praktikum1/inet.h @@ -0,0 +1,19 @@ +/************************************************************************ + * Definitions for TCP and UDP client/server programs. + */ + +#include +#include +#include +#include +#include +#include +#include + + + + + +#define SERV_TCP_PORT 9018 +//#define SERV_HOST_ADDR "10.0.0.200" /* host addr for server */ +#define SERV_HOST_ADDR "127.0.0.1" /* Localhost */ diff --git a/Bachelor/Verteilte Systeme/Praktikum1/tcpcli.cpp b/Bachelor/Verteilte Systeme/Praktikum1/tcpcli.cpp new file mode 100644 index 0000000..ac10492 --- /dev/null +++ b/Bachelor/Verteilte Systeme/Praktikum1/tcpcli.cpp @@ -0,0 +1,129 @@ +/************************************************************************ + * + * Example of client using TCP protocol. + * + ***********************************************************************/ +#include +#include "inet.h" +#include "error.cpp" +#include "util.cpp" +#include +using namespace std; + +const int MAXLINE=255; // max length of a line + +// send message msg to server and receive response in resp +void mySend(int sockfd, char *msg, char *resp) { + + + int n; // Länge des Strings + // Daten senden + n = strlen(msg); + if (writen(sockfd, msg, n) != n) + err_sys("str_cli: writen error on socket"); // Fehler beim Schreiben + + // Daten empfangen + n = readline(sockfd, resp, MAXLINE); + if (n < 0) + err_dump("str_cli: readline error"); + resp[n] = 0; /* null terminate */ +} + + +void str_cli(FILE *fp, int sockfd) +{ + int n; + char sendline[MAXLINE], recvline[MAXLINE + 1]; + + + + // Auswahl der Optionen (Eintragen / Suchen) + int m_Auswahl = '0'; + + while (true) { + + cout<<"Telefonbuch\n\nBitte auswählen:\n"; + cout<<" 1: eintragen\n"; + cout<<" 2: suchen\n"; + cout<<" 3: beenden\n"; + cin>>m_Auswahl; + switch (m_Auswahl) { + case (1): + // Neuen Eintrag im Telefonbuch + cout<<"Eintragen:\n"; + char m_Name[50]; + char m_Tel[50]; + + cout<<"Name: "; scanf("%s", &m_Name); strcat(m_Name, "\n"); + cout<<"Tel: "; scanf("%s", &m_Tel); strcat(m_Tel, "\n"); + + mySend(sockfd, "addEntry\n", recvline); + if (strcmp(recvline,"OK\n") != 0) + printf("Error: %s\n", recvline); + mySend(sockfd, m_Name, recvline); + if (strcmp(recvline,"OK\n") != 0) + printf("Error: %s\n", recvline); + mySend(sockfd, m_Tel, recvline); + if (strcmp(recvline,"OK\n") != 0) + printf("Error: %s\n", recvline); + break; + case (2): + // Eintrag im Telefonbuch suchen + cout<<"Suchen\n"; + char m_Search[50]; + cout<<"Name: "; scanf("%s", &m_Search); strcat(m_Search, "\n"); + + mySend(sockfd, "searchEntry\n", recvline); + if (strcmp(recvline,"OK\n") != 0) + printf("Error: %s\n", recvline); + mySend(sockfd, m_Search, recvline); + printf("Ergebnis: %s\n", recvline); + + break; + case (3): + mySend(sockfd,"end\n",recvline); + cout<<"Client beendet...\n"; + return; + break; + default: + cout<<"Falsche Eingabe\n"; + break; + } + } + + +} +/***********************************************************************/ + +/************************************************************************ + * main function, client for TCP/IP echo server + */ +int main(int argc, char** argv) +{ + int sockfd; + struct sockaddr_in serv_addr; + + pname = argv[0]; + + // Fill in the structure "serv_addr" with the address of the + // server that we want to connect with. + bzero((char *) &serv_addr, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = inet_addr(SERV_HOST_ADDR); + serv_addr.sin_port = htons(SERV_TCP_PORT); + + // Open a TCP socket (an Internet stream socket). + if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + err_sys("client: can't open stream socket"); + + // Connect to the server. + if (connect(sockfd, (struct sockaddr *) &serv_addr, + sizeof(serv_addr)) < 0) + err_sys("client: can't connect to server"); + + str_cli(stdin, sockfd); /* do it all */ + + close(sockfd); + exit(0); +} +/***********************************************************************/ diff --git a/Bachelor/Verteilte Systeme/Praktikum1/tcpserv.cpp b/Bachelor/Verteilte Systeme/Praktikum1/tcpserv.cpp new file mode 100644 index 0000000..e23418e --- /dev/null +++ b/Bachelor/Verteilte Systeme/Praktikum1/tcpserv.cpp @@ -0,0 +1,226 @@ +static char rcsid[] = "$Id: tcpserv.c,v 1.1 2001/12/02 12:13:52 as Exp as $"; +/************************************************************************ + * + * Example of server using TCP protocol. + * + ***********************************************************************/ + +#include +#include // open() +#include "inet.h" +#include "error.cpp" +#include "util.cpp" +#include + +#include +#include + +using namespace std; + +// Constant definitions +// +// maximum line length +const int MAXLINE=255; + +// structure for phone book records +struct telEintrag { // Einzelne Einträge im Telefonbuch + char name[50]; + char tel[50]; +}; + +// max. 50 records in a phone book +// global variables +// +// TODO: change to file or shared memory +// global variables are not good with fork() +// +telEintrag telBuch[50]; // 50 Einträge möglich +int telCount = 0; // Position des nächsten freien Platzes + +// write a line to socket sockfd +void myWrite(int sockfd, char *line) { + int n; + // send reply + n = strlen(line); + if (writen(sockfd, line, n) != n) { + err_dump("str_echo: writen error"); + } +} + +// read line from socket sockfd +void myRead(int sockfd, char *line) { + int n; + + + // receive data into line + n = readline(sockfd, line, MAXLINE); + + // error handling + if (n == 0) { + return; /* connection terminated */ + } + else if (n < 0) { + err_dump("str_echo: readline error"); + } + + + // console logging + + // time_t structure variable myTime + time_t myTime; + + // read time into myTime + time(&myTime); + + // char array for time conversion + char tmpTime[25]; + + // copy converted time into char array + strcpy(tmpTime, ctime(&myTime)); + + // append string terminating binary 0 + tmpTime[strlen(tmpTime)-1] = '\0'; + + // print time and received line to stdout + printf("[%s] Nachricht: %s",tmpTime,line); + +} + + +void str_echo(int sockfd) +{ + int n; + char line[MAXLINE]; + + + for ( ; ; ) { + // read line from socket + myRead(sockfd, line); + + // if "addEntry"-command was sent + if (strcmp(line, "addEntry\n") == 0) { + // send back "OK", we understood the command + myWrite(sockfd, "OK\n"); + + // now we receive the name + myRead(sockfd, line); + // name received + myWrite(sockfd, "OK\n"); + // save it in local memory + strcpy(telBuch[telCount].name, line); + + // now we receive the phone number + myRead(sockfd, line); + // number received + myWrite(sockfd, "OK\n"); + // save the number in local memory + strcpy(telBuch[telCount].tel, line); + // next time we fill the next array element + telCount++; + // we did it + printf("Neuer Eintrag im Telefonbuch.\n"); + + } else + // the "searchEntry"-command was sent + if (strcmp(line, "searchEntry\n") == 0) { + // send back "OK", we understood the command + myWrite(sockfd, "OK\n"); + + // receive the search string + myRead(sockfd, line); + // search the entry + int i=0; + bool found = false; + for (i; i < telCount; i++) { + + if (strcmp(telBuch[i].name, line) == 0) { + found = true; + // we found an entry + // send back the phone number + myWrite(sockfd, telBuch[i].tel); + } + } + // we did not find anything + if (found == false) + myWrite(sockfd, "Nicht gefunden.\n"); + + } else if (strcmp(line,"end\n")==0) + { + // client sent end command + // exiting... + myWrite(sockfd,"Server exiting... \n"); + exit(0); + } + else + { + // an undefined command was sent from client + myWrite(sockfd, "Command not found.\n"); + + } + + + } +} +/***********************************************************************/ + +/************************************************************************ + * main function, server for the TCP/IP echo server + */ +int main(int argc, char **argv) +{ + int sockfd, newsockfd, clilen, childpid; + // structures of socket addresses + struct sockaddr_in cli_addr, serv_addr; + pname = argv[0]; + + // Open a TCP socket (an Internet stream socket). + if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + err_dump("server: can't open stream socket"); + + // Bind our local address so that the client can send to us. + + // make sure zeros are in serv_addr + bzero((char *) &serv_addr, sizeof(serv_addr)); + // now fill in information, which we need + serv_addr.sin_family = AF_INET; + // INADDR_ANY: System definiton -> accept connections on every interface + // htonl: convert byte order (host to network long) + serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); + // SERV_TCP_PORT defined in inet.h + // htons: convert byte order (host to network short) + serv_addr.sin_port = htons(SERV_TCP_PORT); + + // bind sockfd to socket address serv_addr (Server) + if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) + err_dump("server: can't bind local address"); + + // mark socket to accept connections + // limit 5 connections backlog in queue + listen(sockfd, 5); + + for ( ; ; ) { + // Wait for a connection from a client process. + // This is an example of a concurrent server. + + clilen = sizeof(cli_addr); + // make new socket for client connection and return + // the file descriptor of this socket + newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, + (socklen_t *) &clilen); + + if (newsockfd < 0) + err_dump("server: accept error"); + + if ( (childpid = fork()) < 0) + err_dump("server: fork error"); + + else if (childpid == 0) { // child process + printf("Verbinung aufgebaut.\n"); + close(sockfd); // close original socket + str_echo(newsockfd); // process the request + exit(0); + } + close(newsockfd); // parent process + } +} +/***********************************************************************/ diff --git a/Bachelor/Verteilte Systeme/Praktikum1/util.cpp b/Bachelor/Verteilte Systeme/Praktikum1/util.cpp new file mode 100644 index 0000000..88c8f66 --- /dev/null +++ b/Bachelor/Verteilte Systeme/Praktikum1/util.cpp @@ -0,0 +1,86 @@ +/************************************************************************ + * + * Utility functions to use with sockets + * + ************************************************************************ + +/************************************************************************ + * + * Read "n" bytes from a descriptor. + * Use in place of read() when fd is a stream socket. + */ +#include +using namespace std; + +int readn(int fd, char* ptr, int nbytes) +{ + int nleft, nread; + + nleft = nbytes; + while (nleft > 0) { + nread = read(fd, ptr, nleft); + if (nread < 0) + return(nread); /* error, return < 0 */ + else if (nread == 0) + break; /* EOF */ + + nleft -= nread; + ptr += nread; + } + return(nbytes - nleft); /* return >= 0 */ +} +/************************************************************************ + +/************************************************************************ + * + * Read a line from a descriptor. Read the line one byte at a time, + * looking for the newline. We store the newline in the buffer, + * then follow it with a null (the same as fgets(3)). + * We return the number of characters up to, but not including, + * the null (the same as strlen(3)). + */ +int readline(int fd,char* ptr, int maxlen) +{ + int n, rc; + char c; + + for (n = 1; n < maxlen; n++) { + if ( (rc = read(fd, &c, 1)) == 1) { + *ptr++ = c; + if (c == '\n') + break; + } else if (rc == 0) { + if (n == 1) + return(0); /* EOF, no data read */ + else + break; /* EOF, some data was read */ + } else + return(-1); /* error */ + } + + *ptr = 0; + return(n); +} +/************************************************************************ + +/************************************************************************ + * + * Write "n" bytes to a descriptor. + * Use in place of write() when fd is a stream socket. + */ +int writen(int fd, char* ptr, int nbytes) +{ + int nleft, nwritten; + + nleft = nbytes; + while (nleft > 0) { + nwritten = write(fd, ptr, nleft); + if (nwritten <= 0) + return(nwritten); /* error */ + + nleft -= nwritten; + ptr += nwritten; + } + return(nbytes - nleft); +} +/************************************************************************/ -- cgit v1.2.3