netstat:myth66:/usr/class/cs110/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 0.0.0.0:10050 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 :::10050 :::* LISTEN -
tcp6 0 0 :::22 :::* LISTEN -
myth66:/usr/class/cs110/lecture-examples/networking$Chris Gregg contributed to these slides.
myth66:/usr/class/cs110/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 0.0.0.0:10050 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 :::10050 :::* LISTEN -
tcp6 0 0 :::22 :::* LISTEN -
tcp6 0 0 ::1:631 :::* LISTEN -
myth66:/usr/class/cs110/lecture-examples/networking$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.
write's return value could very well be less than what was supplied by the third argument. For example, you may try to publish the contents of a 62GB movie and be told that only 4MB went through.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 precisely 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 clientiosockstream 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 5) 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 below.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;
}