 Whereas an IP packet header conveys the source and destination IP addresses, a UDP datagram header specifies source and destination port numbers. These port numbers, 16-bit values ranging from 0 to 65,535, effectively specify which processes are sending and receiving the packet. By convention, you'll see ports written after a colon following an IP address. This for instance specifies port 80 at address 106.3.0.26. When a process listens for incoming UDP datagrams, it chooses a particular destination port and the OS will, usually, only allow one process at a time to listen to a particular destination port. When sending UDP datagrams, a process also specifies a particular source port, but generally a source port can be used by multiple processes simultaneously. For some networking applications, there is a so-called well-known port number. Web servers, for example, almost always use TCP port 80. FTP servers, for another example, usually use TCP port 20. Understand that TCP and UDP ports are separate address spaces, so say TCP port 80 is a different port than UDP port 80. Now, looking at the details of a UDP header, we have the source and destination port numbers as discussed, but then also have a field designating the length of the entire UDP datagram, and then a checksum that covers not just a datagram, but also a pseudo-header, meaning parts of the containing IP header, including the source and destination IP addresses. By checksum in this information, the receiver of a UDP datagram doubly ensures that the datagram didn't get misrouted. That's really all there is to UDP headers. TCP headers are a bit more complicated. Like a UDP header, a TCP header includes source and destination ports, and a checksum that covers both the TCP segment itself and a pseudo-header of the containing IP packet. Strangely, a TCP header specifies its own length, but not the length of the segment's data. Instead, the length of the segment data is inferred from the length of the containing IP packet minus the length of the TCP and IP headers. I honestly have no idea why UDP and TCP handle this differently. To provide reliability, a TCP header also includes a sequence number, an acknowledgement number, and a field of nine flags, only three of which we'll concern ourselves with, acknowledge, synchronize, and finish. A TCP header also includes three reserved bits, a window size, an urgent pointer, and options, but we won't discuss these things. When two processes exchange data over TCP, they form a connection, and each TCP connection represents two streams of bytes, one going in each direction. What the sequence number of a header signifies is which bytes of the stream are included in the segment. The acknowledgement number, meanwhile, tells the other side of the connection that every byte of the stream up to n has been received. For example, a segment with 20 bytes of data and sequence number 100 represents the bytes 100 to 119 of the stream of bytes being sent from this side of the connection. A segment with acknowledgement number 350 tells the other side of the connection that every byte up to, but not including, byte 350 of the stream coming from the other side of the connection has been received. Remember that these data streams are split into separate segments which may arrive out of order, and so the received data of a stream may have gaps. The acknowledgement number, however, indicates the leading part of the stream without gaps, so if our side of the connection received every byte up to byte 350 and also bytes 470 up to 600, the acknowledgement number we send will still be 350, not 600. When a segment is sent with the synchronized or finished flags, whose purposes we'll explain shortly, those flags themselves count as a byte of data in the stream. So after we receive a segment with a synchronized or finished flag, the acknowledgement number we next send should be incremented by one. In a segment without the synchronized or finished flag set and without bytes of data, the sequence number field is ignored. Likewise, in a segment without the acknowledged flag sent, the acknowledgement number field is ignored. In general, the acknowledged flag will be set in every segment except the very first one sent to establish a connection. When a sender does not receive an acknowledgement for bytes sent within a certain amount of time, it will automatically resend every byte past the last received acknowledgement number. The length of time a sender waits for acknowledgement is a configurable option of the sender and may fluctuate based on network congestion. Typical wait times range from a few seconds up to 30 or 60 seconds on the high end. Before two hosts start exchanging data over TCP, they first must establish a connection using what's called a three-way handshake. Say we have some server listening on a TCP port. The client first sends to that port a segment with no data, the synchronized flag set, and an initial sequence number. For security reasons, initial sequence numbers are generally chosen at random. The server then responds with its own segment with no data, a synchronized and acknowledged flag set, its own randomly chosen initial sequence number, and an acknowledgement number which is one greater than the sequence number which it received from the client. Once the client receives this response, it sends another segment, this time with just the acknowledged flag set, and an acknowledgement number that is one greater than the sequence number which it received from the server. After this three-way handshake, both sides of the connection have shared their randomly chosen sequence numbers and gotten acknowledgement of those numbers so both sides are ready to send and receive data. Looking at an example connection, first the client sends a segment with the synchronized flag and the sequence number 3040, chosen at random. The server then responds with the synchronized and acknowledged flag set, a sequence number of its own random choosing, and the acknowledgement number 3041. The client completes the handshake with the acknowledgement number 700201. Both sides are now ready to exchange data and so let's say the client sends a segment with 20 bytes of data. This segment will have the sequence number 3041 indicating that the data starts with byte 3041 of the stream sent from the client to the server. Remember that the synchronized flag itself was byte 3040. Even though the client already sent acknowledged number 700201, the client sends it again anyway because the acknowledgement number field is included in every segment header, so we might as well. Once receiving the segment, the server responds with acknowledgement number 3061. If the client doesn't get this acknowledgement within the time limit, it will resend the data. If somehow the server ends up receiving redundant segments with overlapping data, this isn't a problem because the sequence numbers always indicate where the bytes should fit in the stream of data. So let's be clear what the stream of data from the client to the server looks like so far. The synchronized flag itself represents sequence number 3040 of the stream and then the 20 bytes we just sent represent sequence numbers 3041 through 3060. Keep in mind that the stream of bytes from the server to the client is a separate stream with its own sequence numbers. At the moment though, our server hasn't sent any data bytes to the client. As a simple optimization, a host may choose to wait a little while before sending acknowledgments. Here for example, say our client sends the server two segments one after the other. If our server waits a little while before sending acknowledgments, it might receive both of these segments before sending an acknowledgement and so only needs to send one acknowledgement rather than two. In some cases, a host can avoid sending an acknowledgement only segment because it is itself sending data over the connection. Here for example, after receiving a 20 byte data segment from the client, the server sends the client a 55 byte segment and this segment like all segments includes the latest acknowledgement number. So the server needn't send an acknowledgement only segment. But assuming the client doesn't have any more data to send any time soon, it must send an acknowledgement only segment. In this scenario, the client sends two segments of data but the first doesn't reach the server. Because the server has the bytes starting at sequence number 3061 but not the bytes 3041 to 3060, any acknowledgement the server now sends will still have 3041 as the acknowledgement number. And so after a short time, the client will decide that it needs to resend everything starting from sequence number 3041. Notice there is some inefficiency here. If TCP acknowledgments were more specific about what bytes have been received, the client would know exactly which bytes the server hasn't received and so would only need to resend those. In most cases, however, TCP's cruder system of sequence and acknowledgement numbers suffices without imposing much overhead. When one side of a TCP connection decides it will never again send data over this connection, it should send a segment with the finish flag. The other side of the connection should then acknowledge this. Here is the same three-way handshake we saw earlier. If the client has no intention of sending any data over this new connection, it should immediately send a segment with the finish flag set and the server should then acknowledge this with an incremented acknowledgement number. Remember that the finish flag, like the synchronized flag, is counted as a byte in the stream with its own number in the sequence. Now, when one side of a connection closes its stream with the finish flag, the other side is under no obligation to close its end too, so the server here could continue to send the client as much data as it likes. Once done sending data, however, the server should close its end with the finish flag as well. Here, for example, the server immediately closes its end after the client does. Once both sides have closed the connection, the connection is fully closed and so discarded by the hosts at both ends.