Client-server programming is a nifty little paradigm you use every day: to browse the web, to send e-mails, to connect to the inst machines, and to play online games. The idea is that a number of client machines connect to a server, and ask the server for various things (send this e-mail for me, get the contents of this web page). One common use of the server is to interact with other clients (IM this person, start a StarCraft game with that person).
We're going to use the IM client and server from lecture and lab as an example program for this discussion.
Let's pause to go over some
buzzwords terminology here. These are the big ideas of our short demo of client-server programming.
- A request is sent over the network in order to cause an action and/or receive a response. In our IM program, requests have source, destination, command (just a word), and data fields. The IM request ADT is defined in im-common.scm.
- Broadcasting means sending a request to "everybody". In the IM program, the server procedure
server-broadcastprovides a way to send a given command and data to every connected client.
- A connection is a "pipe" of sorts between two machines; data can flow in both directions. It is an abstract concept built on top of the lower-level TCP/IP specifications. The "near" end of the connection is called "local", and the "far" end is called "remote".
- A socket is one end of a connection. Sockets have unique ID numbers (confusingly called port numbers; see below). Sockets are provided by the OS.
- Each socket has two ports, an input port for reading from and an output port for writing to. So, anything you write to a socket's output port will be sent along the connection to the remote socket's input port.
- A callback is a procedure that is called in response to some event. For example, when the IM client's
port-from-serverreceives data, it calls the
It's worth noting that callbacks are used all over the place, not just in client-server programming.
Using the IM application is pretty easy. You just
im-enroll with the server you want, and
im the people you want to talk to. When you're done,
im-exit lets you disconnect cleanly from the server. Open up the source files, though, and there's a lot more going on…
Even this leaves out a bunch of error-handling (and logging) that's going on in the code. For instance, the
im procedure looks like this:
(define (im who message) ;;;Send message to who. (if (not (send-request (make-request whoiam who 'send-msg message) port-to-server)) (close-connection)))
This takes advantage of the fact that the
send-request procedure is set up to return
#f if there's a problem in sending the request. If there was a problem, we should clean up after ourselves.
#t, does that mean the server got the message? Not necessarily! The request could still get lost on AirBears, or blocked by the server's firewall, or any number of problems. With networking, there's no way to tell if your message failed, or if it's just taking a long time.
As for how the request is actually sent, it's broken down into fixed-sized chunks called packets, which are tagged with the source and destination addresses (those strings like 126.96.36.199, eventually to be replaced by a longer ID like 0:0:ffff:0:0:8020:2a1b), the source and destination port numbers (which identify sockets, remember), and a few other things, like a connection ID. These packets are then fired across the network from computer to router to ISP, across the Internet, and down to a computer again—or just computer to router to computer on the same network, and just within the computer when you have two programs on star.cs talking to each other. You'll learn more about this if you take CS 162 Operating Systems.
What's the difference between client and server? They both have sockets and ports. They both send and receive requests. They seem pretty similar.
Indeed, the only difference between clients and servers is one of responsibility. That is, they do different things. In the IM program, it's the server's responsibility to keep track of all clients, and to match client names up with the correct connections. This way, the clients don't have to keep track of this stuff. (Notice that clients never send requests to each other, only to the server.)
This isn't fixed, however. You can have a networked system in which everyone behaves equally, rather than communicating with a central source. In this case, every "client" functions as a peer; this is what "peer-to-peer" file-sharing means.
Often, there's still a central "server" that keeps track of everyone who's online. But when one peer wants to talk to another, they just do so directly, rather than having the server forward all messages to their final destinations.