 UDP and TCP are both used to send data between processes, but for some purposes the operating systems which control the IP, UDP, and TCP stacks on our systems need to communicate with each other. This is done with ICMP, the Internet Control Message Protocol. It's arguable where ICMP fits in the four-layer model. In some ways it acts like a transport layer because, like TCP and UDP, ICMP messages are carried directly in IP packets. On the other hand, ICMP generally concerns routing issues, so it is more commonly considered part of the Internet layer, along with IP itself. An ICMP message has a header, and then in some cases a chunk of data. Each ICMP header has a type field, a code field, and a check sum. Together, the type and code fields indicate the nature of the message. For some combinations, the type and code convey the entire message, but for many combinations, more data is included with the message. For example, when an incoming packet attempts to reach an invalid port, the receiving host sends back an ICMP message of type 3 code 3 with a header of the IP packet that attempted to access the invalid port. For another example, when a router discards a packet whose time to live expires, it sends to the packet's original sender an ICMP message of type 11 code 0 with a header of the discarded IP packet. We won't cover the rest of the ICMP messages, but most of them, like these two examples, signal some kind of error. Now that we've covered the Internet and Transport layers, let's look at one of the most pervasively used application layer protocols, HTTP. Like most application protocols, HTTP is used exclusively over TCP and never UDP because it requires reliability. It wouldn't do if our HTTP requests and responses were not delivered in full. The basic idea of HTTP is that everything is triggered by requests sent from a client to a server. Unlike in some other application protocols, the server only sends data to the client when prompted by a request. Each request is discrete, with no connection state maintained between requests. HTTP requests come in several kinds, called methods. We'll only look at the two request methods which are by far most commonly used, get and post. In a get request, the client sends a URL to the server and the server sends back a response appropriate to that URL. For example, when my web browser sends a get request with the URL example.com slash pizza, the web server at example.com will send back whatever is associated with the path pizza and when my web browser sends a get request with the URL example.com slash hamburger, the web server at example.com will send back whatever is associated with the path hamburger. What exactly is the appropriate response for those URLs is entirely up to the web server receiving the request. The HTML of a typical web page often includes other URLs, such as for images and other resources. These other resources are retrieved by the browser with additional GET requests. Here you can see that visiting the front page of nytimes.com triggers many such requests. In fact, checking nytimes.com right now, my browser tells me that it made over 200 requests for just this one page. A POST request is very much like a GET request, except that a POST request also additionally includes bytes of data. Like with the path of a URL, the significance of this data is entirely up to the interpretation of the web server. POST requests are most commonly used when submitting form data on a web page. The form data is passed as data of a POST request to the web server, and then the web server may do whatever it wishes with that data, such as stored in a database. In the response to a POST, the server typically sends back a page acknowledging receipt of the data or possibly indicating some kind of error with the data. Here we see an example GET request. The request starts with a line specifying the request method GET, the URL path, in this case just slash, and the version of HTTP, in this case 1.1. After the first line, we have the request headers, each written on its own line and starting with the name of the header. Starting with the first line of the request, these headers are expressed strictly in ASCII only text. The headers may be written in any order. Here we see two headers, HOST and USER agent. HOST indicates the HOST portion of the URL, in this case Google.com. The USER agent identifies the make and version of the browser sending the request. For this request, I used Firefox 3.6.10, but as you can see, the USER agent string contains a bunch of other junk, such as the name and version of my operating system as well as the name of the rendering engine GECO, used by this version of Firefox. Some web servers may wish to know this information so that they can best customize their responses for the user's machines. After these two headers, we have four more headers. The accept header specifies which resource formats the request sender is ready to receive, accept language specifies the preferred languages, accept encoding specifies which compression schemes this browser can decompress, accept char set specifies which character sets and encodings are preferred for resources in textual formats, such as HTML. We then have four more headers. The keep alive and connection headers here are used in conjunction with what are called persistent TCP connections. For the sake of efficiency, we don't want to use separate TCP connections for each ATP request to a server if we're going to be making many requests one after the other. The keep alive connection allows us to reuse one TCP connection for many successive HTTP requests. The keep alive header value indicates the time and seconds which the client wants the server to wait after each request before dropping the TCP connection. The cookie header includes any cookies stored by the browser for this domain. In HTTP responses, a server may include cookies, small pieces of data which are stored by the browser and then sent by the browser in any subsequent request to that same domain. Most commonly, cookies are simple identifiers that websites use to identify repeat visitors. By the way, for security reasons, I've garbled the cookie you see here. A real cookie probably won't have ASDF repeated many times. Lastly, this cache control header tells a server that this client doesn't want a cached copy of the resource and so the resource should be sent back in the response regardless of the resource's age. So that's the entirety of this get request. Mainly a bunch of headers written in ASCII text. When the server sends back an HTTP response, the first line includes a three-digit status code. Codes beginning with one indicate that the response is informational. Codes beginning with two indicate a successful request. Codes beginning with three indicate that the request requires redirection, meaning the request should be resented to another URL. Codes beginning with four indicate that the client made an error in its request. Codes beginning with five indicate that something went wrong on the server's part. Here we have a response with status code 200 indicating an ordinary successful response. The first line specifies the version of HTTP, the response code, and a response message, which is a human-friendly message generally ignored by the client. For status code 200, the response message is traditionally OK. After this first line, we have the response headers. The most important of these headers are self-explanatory. For example, content-length header indicates the length of the response's content in bytes. The response's content itself starts after a blank line after the last header.