Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 52

TCP Client Socket Workflow

Recommended resources

Introduction

Hello! In the last lesson, we explored the server's role in establishing a TCP connection. We saw how a server uses socket(), bind(), listen(), and accept() to passively wait for clients to initiate contact. This is like a business setting up a phone line and waiting for calls.

Today, we'll switch perspectives and look at the client's side of the equation. How does a program actively reach out and connect to a listening server? This lesson covers exactly that, focusing on the two key system calls a TCP client uses. Your goal for this lesson is to describe the sequence of socket API calls for a typical TCP client (socket, connect).

By the end of this lesson, you'll understand the "active open" process that complements the server's "passive open," completing the picture of how a TCP connection is born.


The Client's Lifecycle: Actively Seeking a Connection

While a server listens, a client initiates. Think of it as making a phone call. You know the number you want to dial (the server's IP address and port), you pick up your phone (create a socket), and you dial the number (connect).

This sequence is simpler than the server's:

  1. socket(): Get a communication endpoint from the operating system. This is identical to the server's first step.
  2. connect(): Use that socket to establish a connection with a specific server at a known address and port.

The diagram below illustrates this client-side flow in contrast to the server's flow, which we covered last time. Today, we're focusing on the "Client" column.

State Diagram for Server and Client Model of Socket
This diagram shows the sequence of API calls for a server (left) and a client (right). Note the client's simpler path: `socket()` followed by `connect()`, which triggers the server's `accept()` call.

Step 1: socket() - Creating the Endpoint (A Recap)

Just like the server, the first thing a client must do is request a socket from the operating system.




#include <sys/types.h>
#include <sys/socket.h>

int sockfd = socket(AF_INET, SOCK_STREAM, 0);

As a brief reminder from our last lesson:

  • AF_INET specifies the IPv4 Internet protocol family.
  • SOCK_STREAM specifies a reliable, stream-oriented socket (TCP).
  • 0 lets the OS choose the default protocol, which is TCP for SOCK_STREAM.

This call returns a socket descriptor (sockfd), an integer that acts as a handle for our endpoint. At this stage, it's just a generic endpoint, not associated with any destination.


Step 2: connect() - Initiating the Connection

This is the pivotal step for the client. The connect() function takes our newly created socket and attempts to establish a connection with a remote server.




#include <sys/socket.h>

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

Let's break down the parameters:

  • sockfd: The file descriptor returned by our call to socket().
  • addr: A pointer to a struct sockaddr containing the destination server's IP address and port number.
  • addrlen: The size of the address structure.

Preparing the Server Address

Before you can call connect(), you must first populate a structure with the server's address information. In modern C programming, the best way to do this is with the getaddrinfo() function. It's a powerful helper that handles looking up domain names (like www.google.com) and preparing the sockaddr structures for you, and it works seamlessly with both IPv4 and IPv6.

The following guide is an excellent, comprehensive resource for socket programming. We will refer to it frequently.

Beej's Guide to Network Programming

Let's turn to the renowned "Beej's Guide to Network Programming" to understand the modern approach for preparing address structures. This section explains getaddrinfo() and shows how a client uses it to look up a server's address.

Read the section 'getaddrinfo()—Prepare to launch!'. Focus on the client example, which shows how to set up the hints struct and call getaddrinfo() to get a linked list of potential addresses for a server.

Making the Call

Once getaddrinfo() provides you with a valid address structure (servinfo in Beej's example), you can finally call connect().

The connect() call is a blocking call. When you call it, your program execution pauses, and the operating system takes over to perform the TCP three-way handshake (SYN, SYN-ACK, ACK) with the server.

  • If successful: The handshake completes, the connection is established, and connect() returns 0. Your socket is now ready for send() and recv() (or write() and read()).
  • If it fails: The server might not be running, a firewall might block the connection, or the address could be wrong. In this case, connect() returns -1, and you should check the errno variable to find out why.

A key point for clients is that you typically do not need to call bind(). The OS will automatically choose an unused local port (an "ephemeral port") for your end of the connection when you call connect().

The following clip provides a fantastic analogy for what the connect() call accomplishes under the hood.

The Linux socket API explained

In this video, 'The Linux socket API explained', the connect function is compared to 'installing the door'. It abstracts away all the complexity of the three-way handshake, just as a carpenter handles the details of hanging a door.

Watch from 04:32 to 05:43. Pay close attention to how connect takes the abstract socket and the server's address and turns them into a ready-to-use, reliable connection.


A Practical Walkthrough: Building a Web Client

Theory is great, but seeing it in action solidifies the concepts. Let's watch a video where the author builds a simple web client—a program that connects to a web server and fetches the content of a webpage. This is a perfect real-world example of a TCP client.

How to build a web client? (sockets)

This video, 'How to build a web client? (sockets)' from Jacob Sorber's channel, provides a step-by-step C implementation. It will walk you through the entire client process, from creating the socket to connecting and then communicating with a server.

Watch from 02:26 to 04:32. This segment covers the exact sequence we've discussed: socket() (02:26 - 03:17): Creating the socket endpoint. Preparing the Address (03:17 - 04:08): Filling the sockaddr_in struct with the server's IP and port. (Note: This video uses the older inet_pton method, but the principle is the same as with getaddrinfo). connect() (04:08 - 04:32): Making the actual connection to the server.

For a complete, copy-paste ready code example, you can also refer to the simple stream client in "Beej's Guide".

Beej's Guide to Network Programming

To see all the pieces put together in a complete program, review the simple client example from "Beej's Guide". This code uses getaddrinfo(), loops through the results, and attempts to socket() and connect() to the first one that works.

Read the code under the section 'A Simple Stream Client'. Trace the logic: getaddrinfo(), for loop, socket(), connect(). This is a robust pattern for writing client code.


Conclusion

You have now learned the complete sequence of API calls for a TCP client. The process is a straightforward, active initiation of a conversation with a listening server.

Key Takeaways:

  • A TCP client's setup sequence is socket() followed by connect().
  • socket() creates the client's endpoint, returning a socket descriptor.
  • Before connecting, the client must prepare a sockaddr structure containing the server's IP address and port, preferably using getaddrinfo().
  • connect() is a blocking call that initiates the TCP three-way handshake. Upon success, the socket is fully connected and ready for data transfer.
  • The client does not need to call bind(); the kernel assigns a temporary local port automatically.

Preview of the Next Lesson:

You now understand the theory behind both the TCP server and client setup. In the next lesson, we will get our hands dirty with code. You will implement a simple TCP echo client in C that sends data to a server and prints the response, putting the concepts from today's lesson into direct practice.