This document provides a basic example of a TCP client implementation in Windows using C++. This example demonstrates how to establish a connection to a TCP server, send data, and receive data.
A TCP (Transmission Control Protocol) client initiates a connection to a TCP server to exchange data. This involves:
tcp_client.cpp
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#include <string>
#include <vector>
// Link with Ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")
const int DEFAULT_PORT = 27015;
const int BUFFER_SIZE = 4096;
int main(int argc, char** argv) {
WSADATA wsaData;
SOCKET connectSocket = INVALID_SOCKET;
struct addrinfo* result = nullptr, *ptr = nullptr;
struct addrinfo hints;
char recvbuf[BUFFER_SIZE];
int recvbuflen = BUFFER_SIZE;
// Validate and parse command line arguments for server address and port
if (argc != 3) {
std::cerr << "usage: tcp_client <serverip> <port>\n";
return 1;
}
std::string serverIp = argv[1];
std::string portStr = argv[2];
// Initialize Winsock
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
std::cerr << "WSAStartup failed with error: " << iResult << std::endl;
return 1;
}
// Setup hints structure for getaddrinfo
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC; // Allow IPv4 or IPv6
hints.ai_socktype = SOCK_STREAM; // TCP stream sockets
hints.ai_protocol = IPPROTO_TCP; // TCP protocol
// Resolve the server address and port
iResult = getaddrinfo(serverIp.c_str(), portStr.c_str(), &hints, &result);
if (iResult != 0) {
std::cerr << "getaddrinfo failed with error: " << iResult << std::endl;
WSACleanup();
return 1;
}
// Attempt to connect to an address until one succeeds
for(ptr=result; ptr != nullptr ;ptr=ptr->ai_next) {
// Create a SOCKET for connecting to server
connectSocket = socket(ptr->ai_family, ptr->ai_socktype,
ptr->ai_protocol);
if (connectSocket == INVALID_SOCKET) {
std::cerr << "socket failed with error: " << WSAGetLastError() << std::endl;
continue; // Try next address
}
// Connect to server
iResult = connect( connectSocket, ptr->ai_addr, (int)ptr->ai_addrlen );
if (iResult == SOCKET_ERROR) {
std::cerr << "connect failed with error: " << WSAGetLastError() << std::endl;
closesocket(connectSocket);
connectSocket = INVALID_SOCKET;
continue; // Try next address
}
break; // Successfully connected
}
freeaddrinfo(result); // Free the linked list
if (connectSocket == INVALID_SOCKET) {
std::cerr << "Unable to connect to server!\n";
WSACleanup();
return 1;
}
// Send a message to the server
std::string messageToSend = "Hello from the TCP client!";
iResult = send( connectSocket, messageToSend.c_str(), (int)messageToSend.length(), 0 );
if (iResult == SOCKET_ERROR) {
std::cerr << "send failed with error: " << WSAGetLastError() << std::endl;
closesocket(connectSocket);
WSACleanup();
return 1;
}
std::cout << "Bytes Sent: " << iResult << std::endl;
// Receive data from the server
do {
iResult = recv(connectSocket, recvbuf, recvbuflen, 0);
if (iResult > 0) {
std::cout << "Bytes received: " << iResult << std::endl;
std::string receivedData(recvbuf, iResult);
std::cout << "Data: " << receivedData << std::endl;
} else if (iResult == 0) {
std::cout << "Connection closing...\n";
} else {
std::cerr << "recv failed with error: " << WSAGetLastError() << std::endl;
break;
}
} while(iResult > 0);
// Shutdown the connection since no more data will be sent
iResult = shutdown( connectSocket, SD_SEND );
if (iResult == SOCKET_ERROR) {
std::cerr << "shutdown failed with error: " << WSAGetLastError() << std::endl;
closesocket(connectSocket);
WSACleanup();
return 1;
}
// Cleanup
closesocket(connectSocket);
WSACleanup();
return 0;
}
#pragma comment(lib, "Ws2_32.lib")
ensures that the Winsock library is linked to the project.
DEFAULT_PORT
and BUFFER_SIZE
define commonly used values.
WSAStartup()
initializes the Winsock DLL.
socket()
creates a TCP socket. getaddrinfo()
is used to resolve the server's IP address and port into a usable format for the connect()
function.
connect()
attempts to establish a connection with the specified server. The code iterates through possible addresses returned by getaddrinfo()
until a connection is successful.
send()
is used to transmit data to the server.
recv()
reads data from the server into a buffer. The loop continues as long as data is being received.
shutdown()
is called to indicate that no more data will be sent.
closesocket()
closes the connection, and WSACleanup()
uninitializes Winsock.
tcp_client.exe <server_ip_address> <server_port>
For example:
tcp_client.exe 127.0.0.1 27015