In general, transport layer protocols provide various services on top of the network layer that make them suitable for direct use by network applications. Usually, these services are some combination of demultiplexing, reliable data transfer, and congestion control. In practice, more than 90% of the packets on the Internet are TCP packets, so we mainly focus on TCP. However, some applications instead choose to use the Unreliable Datagram Protocol (UDP), so we discuss it briefly as well.
One of the most common features provided by the transport layer protocols is called Demultiplexing. In a nutshell, demutltiplexing refers to sorting incoming packets into different sets of data according to some criterion. Demultiplexing is critical if more than one program on a computer wishes to use the Internet. If your web browser and your email program both need to receive data from the Internet at the same time, they need a mechanism to divide up incoming packets so that the browser doesn't get confused by email packets and so that the email program doesn't get confused by web page packets. TCP and UDP both provide this capability with Ports. When a program sends a TCP or UDP packet to an IP address, it specifies a port number between 1 and roughly 65,000. When the destination computer's operating system receives the packet, it delivers it only to the program that registered itself under that port. Note that while both TCP and UDP use the same notion of ports, the operating system handles each protocol separately. That is to say, there is no inherent connection between TCP port X and UDP port X.
The killer feature of TCP is that it lets programmers write software as if there were a Reliable Stream of data between two computers. In other words, TCP offers a 'pipe' into which one application can send data and rest assured that it will come out of the other end in order and intact. Moreover, the connection is full-duplex (two-way), so there are really two pipes: one going from each computer to the other. This is a great boon for programmers, because they don't need to spend very much time worrying about the details of how their data gets from one computer to another.
However, the inner workings of TCP are probably some of the most complicated among all the protocols on the Internet. This is because IP makes no promises that packets will arrive in the order they were sent or even that they will arrive at all. In order to handle this problem, TCP puts identifiers called Sequence Numbers on each packet it sends. After selecting a random starting number, TCP assigns consecutive sequence numbers to each byte of data in the stream, and labels the sequence number of the first byte of data in each packet. Thus, if a computer receives a TCP packet with 26 bytes of data starting at sequence number 4270, it knows that it has received bytes 4270 through 4295 of the stream. This helps the receiver put the data in the proper order before delivering it to the application.
Unfortunately, packets sometimes get lost. They can be corrupted during transmission between two hops, or they can be dropped by a congested router. Since TCP promises to deliver data reliably, it needs a way to cope with the possibility that not every packet makes it to the destination. While the details are sometimes more complicated, the general mechanism for this is as follows. When the starting sequence number is selected, the receiver creates a series of empty slots for the first few thousand bytes in the sequence. Whenever the receiver gets a packet of data, it checks the sequence numbers that the received bytes correspond to and puts them in the appropriate slots. Whenever the receiver has a series of bytes with no holes starting at the lowest slot, it sends those bytes off to the application and re-labels the slots to make room for higher sequence numbers.
Aside
Apart from ACK, there are several other control packets that TCP uses to manage the connection. These include Synchronize (SYN) to start a connection, Finish (FIN) to end a connection, and Reset (RST) to abruptly terminate a connection. There has been recent controversy over Comcast's decision to interrupt BitTorrent transfers by artificially injecting RST packets into the TCP stream.
In order to communicate its progress back to the sender, the receiver sends an Acknowledgement (ACK) packet back to the sender each time it receives data. The ACK packet indicates the sequence number of the first hole, telling the sender 'I have received everything up to here'. If a sender transmits a packet but does not get an ACK for it within a fixed amount of time, it concludes that the packet was lost and resends the data.
When a a lot of data needs to be sent over the Internet, it might seem efficient for the sender to transmit at the highest possible rate. However, in the early days of the Internet, researchers realized that the Internet would quickly grind to a halt unless careful limits were imposed on the sender. If many packets arrive at a router all at once, the router has no choice but to drop some of them. This, however, triggers retransmissions by the sender, which leads to more dropped packets. If the drops occur at the 18th hop, the resources of 17 routers are wasted forwarding packets that will never arrive. Thus, the designers of TCP added a form of Congestion Control to the protocol to make TCP a better Internet citizen. A sender gradually increases its rate until it encounters a drop, at which point it halves its sending rate and continues as before.
Aside
Despite the fact that congestion control is handled by the end points, routers are not powerless to slow down packets. Using a technique called Random Early Detection (RED), most Internet routers selectively drop single packets from TCP streams when their rates rise above a sustainable level. This means that the sender can get the message to slow down before the buffers in the router fill up. Technologies like RED are critical to the stability and efficiency of the network. However, they rely on classifying and tampering with the streams going through routers, so they are non-neutral under some definitions of net neutrality.
The sender interprets the drop as a sign of congestion in the network, which may not necessarily be true: the packet could have been corrupted in transmission and discarded after a failed CRC check. However, the designers of TCP decided that this mechanism was the best way a sender could detect congestion and slow its rate. This is not to say that other, perhaps better mechanisms have not been tried. Indeed, several researchers have suggested that routers should actively tell senders to slow down when they determine that they are becoming congested. However, for various reasons, such schemes have not caught on, so TCP packet loss detection is the dominant form of congestion control on the Internet today.
TCP tries, come hell or high water, to deliver every byte of data, in order, to the receiver. This is what most applications want, since losing chunks of data adds a huge amount of uncertainty to a program. However, specialized applications that push the limits of the Internet often have their own idea of what should happen when packets are lost. Take, for example, Voice over IP (VoIP) applications like Skype. Skype transmits data in real time, so there's a very small window between when voice data is received and when it is played. If a packet corresponding to a millisecond of audio goes missing, there isn't time for a retransmission. It isn't worth pausing the speech signal to wait for a retransmission, since that would only make the problem more noticeable. Moreover, if the application isn't waiting, the packet isn't worth retransmitting, since it won't arrive in time to be played. Thus, such applications require a more bare-bones protocol, and usually use the Unreliable Datagram Protocol (UDP). UDP allows applications to send and receive individual packets, providing only a demultiplexing service on top of IP. With UDP, applications that want to tame the unreliable network in their own way are free to do so.