Network Programming in C++: From Sockets to Asynchrony
\n\nHave you ever wondered how chats, online games, or web servers work? At the heart of each lies network communication. And if you want to write fast, reliable, and low-level network applications, network programming in C++ is what you need. In this article, we won't just go through theory; we'll write real code: from a simple TCP chat to an asynchronous server using Boost.Asio. Get your IDEs ready — it's going to be interesting!
\n\nWhy C++ for Networks? Three Reasons
\nMany choose Python or Java for network tasks, but C++ offers three key advantages:
\n- \n
- Speed: Minimal overhead, direct access to system calls (syscalls). \n
- Control: You manage memory, buffers, and timings manually. \n
- Ecosystem:
Boost.Asio,libcurl,Poco— powerful libraries for any task. \n
But with great power comes great responsibility: one mistake in socket management and your server will crash. Let's figure out how to avoid this.
\n\nBasics: Sockets and the OSI Model
\nBefore writing code, let's recall what a socket is. It's an abstraction that allows an application to send and receive data over a network. In C++, we work through sys/socket.h (Linux) or winsock2.h (Windows).
TCP vs UDP: When to Use What?
\n- \n
- TCP (SOCK_STREAM): Guarantees delivery, packet order. Ideal for chats, HTTP, databases. \n
- UDP (SOCK_DGRAM): Faster, but no guarantees. Used in streaming, DNS, online games (where packet loss is easier to tolerate than latency). \n
Writing a TCP Server and Client in C++ (Raw Sockets)
\nLet's create a simple echo server. It receives a message and sends it back. This is the classic "Hello, World" of network programming in C++.
\n\nServer Side (echo_server.cpp)
\n#include <iostream>\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <unistd.h>\n#include <cstring>\n\nint main() {\n int server_fd, client_fd;\n struct sockaddr_in address;\n int opt = 1;\n int addrlen = sizeof(address);\n char buffer[1024] = {0};\n\n // 1. Create socket\n if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {\n perror("socket failed");\n exit(EXIT_FAILURE);\n }\n\n // 2. Bind to port (reuse port option)\n if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {\n perror("setsockopt");\n exit(EXIT_FAILURE);\n }\n address.sin_family = AF_INET;\n address.sin_addr.s_addr = INADDR_ANY;\n address.sin_port = htons(8080);\n\n if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {\n perror("bind failed");\n exit(EXIT_FAILURE);\n }\n\n // 3. Listen for incoming connections\n if (listen(server_fd, 3) < 0) {\n perror("listen");\n exit(EXIT_FAILURE);\n }\n\n std::cout << "Server started on port 8080. Waiting for connections..." << std::endl;\n\n // 4. Accept client\n if ((client_fd = accept(server_fd, (struct sockaddr *)&address,\n (socklen_t*)&addrlen)) < 0) {\n perror("accept");\n exit(EXIT_FAILURE);\n }\n\n // 5. Read and send back (echo)\n int valread = read(client_fd, buffer, 1024);\n std::cout << "Received: " << buffer << std::endl;\n send(client_fd, buffer, strlen(buffer), 0);\n std::cout << "Echo reply sent" << std::endl;\n\n close(client_fd);\n close(server_fd);\n return 0;\n}\n\nClient Side (echo_client.cpp)
\n#include <