netstat
command:cgregg@myth59:~/cs110/winter-2019/lecture-examples/networking$ netstat -plnt
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:587 0.0.0.0:* LISTEN -
tcp 0 0 127.0.1.1:53 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN -
tcp6 0 0 :::22 :::* LISTEN -
tcp6 0 0 ::1:631 :::* LISTEN -
cgregg@myth59:~/cs110/winter-2019/lecture-examples/networking$ netstat -plnt
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:587 0.0.0.0:* LISTEN -
tcp 0 0 127.0.1.1:53 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN -
tcp6 0 0 :::22 :::* LISTEN -
tcp6 0 0 ::1:631 :::* LISTEN -
int main(int argc, char *argv[]) {
int server = createServerSocket(12345);
while (true) {
int client = accept(server, NULL, NULL); // the two NULLs could instead be used to
// surface the IP address of the client
publishTime(client);
}
return 0;
}
accept
(found in sys/socket.h
) returns a descriptor that can be written to and read from. Whatever's written is sent to the client, and whatever the client sends back is readable here.
publishTime
function is straightforward:static void publishTime(int client) {
time_t rawtime;
time(&rawtime);
struct tm *ptm = gmtime(&rawtime);
char timestr[128]; // more than big enough
/* size_t len = */ strftime(timestr, sizeof(timestr), "%c\n", ptm);
size_t numBytesWritten = 0, numBytesToWrite = strlen(timestr);
while (numBytesWritten < numBytesToWrite) {
numBytesWritten += write(client,
timestr + numBytesWritten,
numBytesToWrite - numBytesWritten);
}
close(client);
}
while
loop for writing bytes is a bit more important now that we are networking: we are more likely to need to write multiple times on a network.
write
's return value could very well be less than what was supplied by the third argument.FILE *
) or C++ streams (e.g. the iostream
class hierarchy) to layer over data buffers and manage the while
loop around exposed write
calls for us.socket++
that provides exactly this.
socket++
provides iostream subclasses that respond to operator<<
, operator>>
, getline
, endl
, and so forth, just like cin
, cout
, and file streams do.publishTime
.publishTime
:static void publishTime(int client) {
time_t rawtime;
time(&rawtime);
struct tm *ptm = gmtime(&rawtime);
char timestr[128]; // more than big enough
/* size_t len = */ strftime(timestr, sizeof(timestr), "%c", ptm);
sockbuf sb(client);
iosockstream ss(&sb);
ss << timestr << endl;
} // sockbuf destructor closes client
iosockstream
that itself layers over the client socket.sockbuf
class takes ownership of the socket and closes it when its destructor is called.myth-buster
and Assignment 5's aggregate
—where multithreading can significantly improve the performance of networked applications.accept
returns a socket descriptor, spawn a child thread—or reuse an existing one within a ThreadPool
—to get any intense, time consuming computation off of the main thread. The child thread can make use of a second processor or a second core, and the main thread can quickly move on to its next accept
call.ThreadPool
(you'll be implementing one for Assignment 6) to get the computation off the main thread.int main(int argc, char *argv[]) {
int server = createServerSocket(12345);
ThreadPool pool(4);
while (true) {
int client = accept(server, NULL, NULL); // the two NULLs could instead be used
// to surface the IP address of the client
pool.schedule([client] { publishTime(client); });
}
return 0;
}
publishTime
needs to change just a little if it's to be thread safe.gmtime
.gmtime
returns a pointer to a single, statically allocated global that's used by all calls.mutex
to ensure that a thread can call gmtime
without competition and subsequently extract the data from the global into local copy.gmtime_r
. This second, reentrant version just requires that space for a dedicated return value be passed in.gmtime
_r itself is, since it doesn't depend on any shared resources.publishTime
is presented on the next slide.publishTime
:static void publishTime(int client) {
time_t rawtime;
time(&rawtime);
struct tm tm;
gmtime_r(&rawtime, &tm);
char timestr[128]; // more than big enough
/* size_t len = */ strftime(timestr, sizeof(timestr), "%c", &tm);
sockbuf sb(client); // destructor closes socket
iosockstream ss(&sb);
ss << timestr << endl;
}