Employee Learning Initiative

COMP 150-IDS: Internet Scale Distributed Systems (Spring 2016)
COMP 150-IDS
Ping Demonstration Programs
&
Makefile / C++ Hints
Noah Mendelsohn
Tufts University
Email: [email protected]
Web: http://www.cs.tufts.edu/~noah
Copyright 2012, 2013 & 2015 – Noah Mendelsohn
What you should get from today’s session
 A quick look at some details you’ll need to do our programming
assignment, including:
 The framework we’re using
 C++ Exceptions
 A tiny bit about inheritance
 Makefiles
 C/C++ tips and tricks
2
© 2010 Noah Mendelsohn
Working through the
Demo Client
3
© 2010 Noah Mendelsohn
Preamble
Include Framework
and Debug code
#include "c150dgmsocket.h"
#include "c150debug.h"
#include <fstream>
using namespace std;
// for C++ std library
using namespace C150NETWORK;
4
© 2010 Noah Mendelsohn
IMPORTANT!
Needed for
COMP150IDS
Framework!
Preamble
#include "c150dgmsocket.h"
#include "c150debug.h"
#include <fstream>
using namespace std;
// for C++ std library
using namespace C150NETWORK;
5
© 2010 Noah Mendelsohn
Main pingclient Logic
6
© 2010 Noah Mendelsohn
This is not an ordinary
socket…it’s a smart
wrapper around a
socket
Client logic
try {
C150DgmSocket *sock = new C150DgmSocket();
sock -> setServerName(argv[serverArg]);
Establishes us as a
client…and identifies
the server…ports set
based on login id
sock -> write(argv[msgArg], strlen(argv[msgArg])+1);
readlen = sock -> read(incomingMessage, sizeof(incomingMessage));
checkAndPrintMessage(readlen, incomingMessage, sizeof(incomingMessage));
}
catch (C150NetworkException e) {
cerr << argv[0] << ": caught C150NetworkException: " <<
e.formattedExplanation()
<< endl;
}
7
© 2010 Noah Mendelsohn
Client logic
Clients write,
then read
try {
C150DgmSocket *sock = new C150DgmSocket();
sock -> setServerName(argv[serverArg]);
sock -> write(argv[msgArg], strlen(argv[msgArg])+1);
readlen = sock -> read(incomingMessage, sizeof(incomingMessage));
checkAndPrintMessage(readlen, incomingMessage, sizeof(incomingMessage));
}
catch (C150NetworkException e) {
cerr << argv[0] << ": caught C150NetworkException: " <<
e.formattedExplanation()
<< endl;
}
8
© 2010 Noah Mendelsohn
Demo Server
9
© 2010 Noah Mendelsohn
Servers read, then
write
Server logic
try {
C150DgmSocket *sock = new C150DgmSocket();
c150debug->printf(C150APPLICATION,"Ready to accept messages");
while(1)
{
readlen = sock -> read(incomingMessage, sizeof(incomingMessage)-1);
// … WORK WITH MESSAGE HERE
string response = “SOME RESPONSE HERE”;
sock -> write(response.c_str(), response.length()+1);
}
}
catch (C150NetworkException e) {
c150debug->printf(C150ALWAYSLOG,"Caught C150NetworkException: %s\n",
e.formattedExplanation().c_str());
}
10
© 2010 Noah Mendelsohn
Server logic
try {
C150DgmSocket *sock = new C150DgmSocket();
c150debug->printf(C150APPLICATION,"Ready to
while(1)
Framework assumes
responses go to
server/port from
which
we read
accept
messages");
{
readlen = sock -> read(incomingMessage, sizeof(incomingMessage)-1);
// … WORK WITH MESSAGE HERE
string response = “SOME RESPONSE HERE”;
sock -> write(response.c_str(), response.length()+1);
}
}
catch (C150NetworkException e) {
c150debug->printf(C150ALWAYSLOG,"Caught C150NetworkException: %s\n",
e.formattedExplanation().c_str());
}
11
© 2010 Noah Mendelsohn
Inferring who is a server and who is a client
try {
NOTE: The socket class imposes a simple notion of
C150DgmSocket *sock = client/server
new C150NastyDgmSocket(nastiness);
on UDP…
c150debug->printf(C150APPLICATION,"Ready to accept messages");
while(1)
{
Itreadlen
decides
whether
you’re a server or sizeof(incomingMessage)-1);
client based on
= sock
-> read(incomingMessage,
which methods you call first
// … WORK WITH MESSAGE HERE
string response = “SOME RESPONSE HERE”;
sock ->
response.length()+1);
1) write(response.c_str(),
client calls setServer name
then writes
}
}
2) server starts by doing a read.
catch (C150NetworkException e) {
Note a very robust approach for production code, but
handy for these simple programs.
c150debug->printf(C150ALWAYSLOG,"Caught C150NetworkException: %s\n",
e.formattedExplanation().c_str());
}
12
© 2010 Noah Mendelsohn
C++ Inheritance
13
© 2010 Noah Mendelsohn
A super-simple look at C++ Inheritance
Base class “Shape”
class Shape {
private:
Point position;
public:
Point getPosition();
virtual void draw() = 0;
};
14
has draw() method
with no
implementation (=0)
© 2010 Noah Mendelsohn
A super-simple look at C++ Inheritance
class Shape {
private:
Point position;
public:
Point getPosition();
virtual void draw() = 0;
};
Each subclass
provides its own
implementation of
draw()
Class Circle : public Shape {
public:
virtual void draw();
};
Class Square : public Shape {
public:
virtual void draw();
};
15
© 2010 Noah Mendelsohn
A super-simple look at C++ Inheritance
Class shape {
private:
Point position;
public:
Point getPosition();
virtual void draw() = 0;
};
Both classes inherit
postion() method from
parent
Shape *shapeArray[2];
int i;
Class Circle : public Shape {
public:
virtual void draw();
};
Class Square : public Shape {
public:
virtual void draw();
};
16
shapeArray[0] = new Circle();
shapeArray[1] = new Square();
for(i=0; i<2; i++) {
cout <<
shapeArray[i] -> position;
shapeArray[i] -> draw();
}
© 2010 Noah Mendelsohn
A super-simple look at C++ Inheritance
Class shape {
private:
Point position;
public:
Point getPosition();
virtual void draw() = 0;
};
First time calls
Circle::draw,
second time calls
Square::draw
Shape *shapeArray[2];
int i;
Class Circle : public Shape {
public:
virtual void draw();
};
Class Square : public Shape {
public:
virtual void draw();
};
17
shapeArray[0] = new Circle();
shapeArray[1] = new Square();
for(i=0; i<2; i++) {
cout <<
shapeArray[i] -> position;
shapeArray[i] -> draw();
}
© 2010 Noah Mendelsohn
Inheritance and nasty sockets logic
The
C150NastyDgmSocket
class inherits from…
try {
C150DgmSocket *sock = new C150NastyDgmSocket(nastiness);
c150debug->printf(C150APPLICATION,"Ready to accept messages");
while(1)
{
readlen = sock -> read(incomingMessage, sizeof(incomingMessage)-1);
// … WORK WITH MESSAGE HERE
string response = “SOME RESPONSE HERE”;
… C150DgmSocket.
You can use
sock -> write(response.c_str(),
response.length()+1);
}
}
either type here, unless you want to
call methods specific to the “nasty”
class.
catch (C150NetworkException e) {
c150debug->printf(C150ALWAYSLOG,"Caught C150NetworkException: %s\n",
e.formattedExplanation().c_str());
}
18
© 2010 Noah Mendelsohn
C++ Exceptions
19
© 2010 Noah Mendelsohn
C++ Exceptions
try {
C++ has
try/catch/throw for
Exceptions
try clause runs first
C150DgmSocket *sock = new C150DgmSocket();
Any network exception
in try block or
methods called by try
sock -> write(argv[msgArg], strlen(argv[msgArg])+1);
block takes us here
sock -> setServerName(argv[serverArg]);
readlen = sock -> read(incomingMessage, sizeof(incomingMessage));
e is of whatever
checkAndPrintMessage(readlen, incomingMessage, sizeof(incomingMessage));
type was “thrown”
}
catch (C150NetworkException e) {
cerr << argv[0] << ": caught C150NetworkException: " << e.formattedExplanation()
<< endl;
}
20
© 2010 Noah Mendelsohn
C++ Exceptions
 Exceptions are particularly useful for network code…
 …no need to “percolate” return codes through layers of method calls
 Standard COMP 150IDS Exception Class:
throw
throw C150NetworkException("Client received
message that was not null terminated");
When an error occurs, throw an Exception (same as “raise” in other langs):
throw C150NetworkException (or other class)
 Exception classes form a hierarchy…based on class inheritance (no need
for you to worry about that if you don’t know C++ inheritance)
21
© 2010 Noah Mendelsohn
Makefiles
Dependency –based
Command Execution
22
© 2010 Noah Mendelsohn
Makefile variables
# Do all C++ compies with g++
Variables defined this
way…
CPP = g++
CPPFLAGS = -g -Wall -Werror -I$(C150LIB)
# Where the COMP 150 shared utilities live,
including c150ids.a and userports.csv
# Note that environment variable COMP150IDS
must be set for this to work!
…or from
environment…
(this is one reason you
setenv COMP150IDS /comp/150IDS)
C150LIB = $(COMP150IDS)/files/c150Utils/
[… several lines skipped…]
pingclient: pingclient.o $(C150AR) $(INCLUDES)
…used this way
$(CPP) -o pingclient pingclient.o
23
© 2010 Noah Mendelsohn
Targets and dependencies
# Do all C++ compies with g++
The pingclient target
CPP = g++
CPPFLAGS = -g -Wall -Werror -I$(C150LIB)
# Where the COMP 150 shared utilities live,
including c150ids.a and userports.csv
# Note that environment variable COMP150IDS
must be set for this to work!
…depends on
pingclient.o (and
include files, etc.)
C150LIB = $(COMP150IDS)/files/c150Utils/
[… several lines skipped…]
pingclient: pingclient.o $(C150AR) $(INCLUDES)
$(CPP) -o pingclient pingclient.o
24
© 2010 Noah Mendelsohn
What gets run
# Do all C++ compies with g++
CPP = g++
When pingclient is
older than pingclient.o,
etc. …
CPPFLAGS = -g -Wall -Werror -I$(C150LIB)
# Where the COMP 150 shared utilities live,
including c150ids.a and userports.csv
# Note that environment variable COMP150IDS
must be set for this to work!
C150LIB = $(COMP150IDS)/files/c150Utils/
[… several lines skipped…]
..use g++ to relink it
pingclient: pingclient.o $(C150AR) $(INCLUDES)
$(CPP) -o pingclient pingclient.o
25
© 2010 Noah Mendelsohn
Fancier dependencies
Each xxx.o file
…depends on xxx.cpp
%.o:%.cpp $(INCLUDES)
$(CPP) -c $(CPPFLAGS) $<
…and is compiled from
that .cpp file
26
© 2010 Noah Mendelsohn
C cs. C++ Strings
27
© 2010 Noah Mendelsohn
C vs C++ Strings – we use both!
 C++ provides automatic allocation and useful concatenation operations
 C char[] arrays needed for formatting message packets
 File and socket APIs defined in terms of C byte arrays
 Also…preference
– For some purposes, printf/scanf are handier than C++ <<
– Etc.
28
© 2010 Noah Mendelsohn
Some hints on strings
 Won’t try a full tutorial here but, remember that you can convert:
char cstring[4] = “abc”;
// remember the null!
string newstring(cstring); // initialize C++ string
// from C string
char *fromCPlusPlus = newstring.c_str();
// IMPORTANT: fromCPlusPlus
// is stable ONLY until
// next change to newstring
 Our focus is on the distributed system design…performance matters
some, but do what’s easy and clean
29
© 2010 Noah Mendelsohn
Stringstreams: useful for formatting and conversions
 C++ strings do not support <<, but stringstreams do
include <sstream>
include <iostream>
// for stringstream
// for cout
stringstream ss;
int answer = 25;
// empty stringstream
ss << “The answer is “<< answer << “ pounds” << endl;
cout << ss.str();
// get string from stringstream
30
© 2010 Noah Mendelsohn
What I Do (mostly)
 I mostly use C++ strings: automatic allocation
 I use or convert to char[] if I’m using APIs that need them
 I use either printf or stringstreams for formatting or…
 …concatenate strings with “+” (slower, and edge cases where it doesn’t
work)
 Not all the framework code makes good choices internally…you’ll find
some stuff that probably should be cleaned up (e.g. excess conversions)
31
© 2010 Noah Mendelsohn