How to implement simple TCP Client and Server Program in C?

Network - TC Client Server in C

This is a C Program that illustrates a simple TCP (Transmission Control Protocol) server that accepts incoming client connections. Once a client connection is established, a thread is spawned to read data from the client and echo it back (if the echo option is not disabled).

You can use any C/C++ Compilers in windows to compile and run this program as it uses winsock2 windows network API.

How to Compile the TCP Client/Server program?

The following TCP Client Server program is divided into two parts, the server and the client. Please compile each program separately as per the following instructions.

Server:

To compile the server program, use the following command line. TCP server accepts incoming client connections. Once a client connection is established, a thread is spawned to read data from the client and echo it back (if the echo option is not disabled).

Compile:

cl -o Server Server.c ws2_32.lib

Command line options:
server [-p:x] [-i:IP] [-o]
-p:x Port number to listen on
-i:str Interface to listen on
-o Receive only, don’t echo the data back

Client:

This sample is the echo client. It connects to the TCP server, sends data, and reads data back from the server.

Compile:
cl -o Client Client.c ws2_32.lib

Command Line Options:

client [-p:x] [-s:IP] [-n:x] [-o]
-p:x Remote port to send to
-s:IP Server’s IP address or hostname
-n:x Number of times to send message
-o Send messages only; don’t receive

Client Source Code

// Module Name: Client.c
//
// Description:
// This sample is the echo client. It connects to the TCP server,
// sends data, and reads data back from the server.
//
// Compile:
// cl -o Client Client.c ws2_32.lib
//
// Command Line Options:
// client [-p:x] [-s:IP] [-n:x] [-o]
// -p:x Remote port to send to
// -s:IP Server's IP address or hostname
// -n:x Number of times to send message
// -o Send messages only; don't receive
//
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>

#define DEFAULT_COUNT 20
#define DEFAULT_PORT 5150
#define DEFAULT_BUFFER 2048
#define DEFAULT_MESSAGE "This is a test of the emergency \
broadcasting system"

char szServer[128], // Server to connect to
szMessage[1024]; // Message to send to sever
int iPort = DEFAULT_PORT; // Port on server to connect to
DWORD dwCount = DEFAULT_COUNT; // Number of times to send message
BOOL bSendOnly = FALSE; // Send data only; don't receive

//
// Function: usage:
//
// Description:
// Print usage information and exit
//
void usage()
{
 printf("usage: client [-p:x] [-s:IP] [-n:x] [-o]\n\n");
 printf(" -p:x Remote port to send to\n");
 printf(" -s:IP Server's IP address or hostname\n");
 printf(" -n:x Number of times to send message\n");
 printf(" -o Send messages only; don't receive\n");
 ExitProcess(1);
}

//
// Function: ValidateArgs
//
// Description:
// Parse the command line arguments, and set some global flags
// to indicate what actions to perform
//
void ValidateArgs(int argc, char** argv)
{
 int i;

 for (i = 1; i < argc; i++)
 {
  if ((argv[i][0] == '-') || (argv[i][0] == '/'))
  {
   switch (tolower(argv[i][1]))
   {
   case 'p': // Remote port
    if (strlen(argv[i]) > 3)
     iPort = atoi(&amp;argv[i][3]);
    break;
   case 's': // Server
    if (strlen(argv[i]) > 3)
     strcpy(szServer, &amp;argv[i][3]);
    break;
   case 'n': // Number of times to send message
    if (strlen(argv[i]) > 3)
     dwCount = atol(&amp;argv[i][3]);
    break;
   case 'o': // Only send message; don't receive
    bSendOnly = TRUE;
    break;
   default:
    usage();
    break;
   }
  }
 }
}

//
// Function: main
//
// Description:
// Main thread of execution. Initialize Winsock, parse the
// command line arguments, create a socket, connect to the
// server, and then send and receive data.
//
int main(int argc, char** argv)
{
 WSADATA wsd;
 SOCKET sClient;
 char szBuffer[DEFAULT_BUFFER];
 int ret,
  i;
 struct sockaddr_in server;
 struct hostent* host = NULL;

 // Parse the command line and load Winsock
 //
 ValidateArgs(argc, argv);
 if (WSAStartup(MAKEWORD(2, 2), &amp;wsd) != 0)
 {
  printf("Failed to load Winsock library!\n");
  return 1;
 }
 strcpy(szMessage, DEFAULT_MESSAGE);
 //
 // Create the socket, and attempt to connect to the server
 //
 sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 if (sClient == INVALID_SOCKET)
 {
  printf("socket() failed: %d\n", WSAGetLastError());
  return 1;
 }
 server.sin_family = AF_INET;
 server.sin_port = htons(iPort);
 server.sin_addr.s_addr = inet_addr(szServer);
 //
 // If the supplied server address wasn't in the form
 // "aaa.bbb.ccc.ddd" it's a hostname, so try to resolve it
 //
 if (server.sin_addr.s_addr == INADDR_NONE)
 {
  host = gethostbyname(szServer);
  if (host == NULL)
  {
   printf("Unable to resolve server: %s\n", szServer);
   return 1;
  }
  CopyMemory(&amp;server.sin_addr, host->h_addr_list[0],
   host->h_length);
 }
 if (connect(sClient, (struct sockaddr*)&amp;server,
  sizeof(server)) == SOCKET_ERROR)
 {
  printf("connect() failed: %d\n", WSAGetLastError());
  return 1;
 }
 // Send and receive data
 //
 for (i = 0; i < dwCount; i++)
 {
  ret = send(sClient, szMessage, strlen(szMessage), 0);
  if (ret == 0)
   break;
  else if (ret == SOCKET_ERROR)
  {
   printf("send() failed: %d\n", WSAGetLastError());
   break;
  }
  printf("Send %d bytes\n", ret);
  if (!bSendOnly)
  {
   ret = recv(sClient, szBuffer, DEFAULT_BUFFER, 0);
   if (ret == 0) // Graceful close
    break;
   else if (ret == SOCKET_ERROR)
   {
    printf("recv() failed: %d\n", WSAGetLastError());
    break;
   }
   szBuffer[ret] = '\0';
   printf("RECV [%d bytes]: '%s'\n", ret, szBuffer);
  }
 }
 closesocket(sClient);

 WSACleanup();
 return 0;
}

Server Source Code

// Module Name: Server.c
//
// Description:
// This example illustrates a simple TCP server that accepts
// incoming client connections. Once a client connection is
// established, a thread is spawned to read data from the
// client and echo it back (if the echo option is not
// disabled).
//
// Compile:
// cl -o Server Server.c ws2_32.lib
//
// Command line options:
// server [-p:x] [-i:IP] [-o]
// -p:x Port number to listen on
// -i:str Interface to listen on
// -o Receive only, don't echo the data back
//
#include <winsock2.h>

#include <stdio.h>
#include <stdlib.h>

#define DEFAULT_PORT 5150
#define DEFAULT_BUFFER 4096

int iPort = DEFAULT_PORT; // Port to listen for clients on
BOOL bInterface = FALSE, // Listen on the specified interface
bRecvOnly = FALSE; // Receive data only; don't echo back
char szAddress[128]; // Interface to listen for clients on

//
// Function: usage
//
// Description:
// Print usage information and exit
//
void usage()
{
 printf("usage: server [-p:x] [-i:IP] [-o]\n\n");
 printf(" -p:x Port number to listen on\n");
 printf(" -i:str Interface to listen on\n");
 printf(" -o Don't echo the data back\n\n");
 ExitProcess(1);
}

//
// Function: ValidateArgs
//
// Description:
// Parse the command line arguments, and set some global flags
// to indicate what actions to perform
//
void ValidateArgs(int argc, char** argv)
{
 int i;

 for (i = 1; i < argc; i++)
 {
  if ((argv[i][0] == '-') || (argv[i][0] == '/'))
  {
   switch (tolower(argv[i][1]))
   {
   case 'p':
    iPort = atoi(&amp;argv[i][3]);
    break;
   case 'i':
    bInterface = TRUE;
    if (strlen(argv[i]) > 3)
     strcpy(szAddress, &amp;argv[i][3]);
    break;
   case 'o':
    bRecvOnly = TRUE;
    break;
   default:
    usage();
    break;
   }
  }
 }
}

//
// Function: ClientThread
//
// Description:
// This function is called as a thread, and it handles a given
// client connection. The parameter passed in is the socket
// handle returned from an accept() call. This function reads
// data from the client and writes it back.
//
DWORD WINAPI ClientThread(LPVOID lpParam)
{
 SOCKET sock = (SOCKET)lpParam;
 char szBuff[DEFAULT_BUFFER];
 int ret,
  nLeft,
  idx;

 while (1)
 {
  // Perform a blocking recv() call
  //
  ret = recv(sock, szBuff, DEFAULT_BUFFER, 0);
  if (ret == 0) // Graceful close
   break;
  else if (ret == SOCKET_ERROR)
  {
   printf("recv() failed: %d\n", WSAGetLastError());
   break;
  }
  szBuff[ret] = '\0';
  printf("RECV: '%s'\n", szBuff);
  //
  // If we selected to echo the data back, do it
  //
  if (!bRecvOnly)
  {
   nLeft = ret;
   idx = 0;
   //
   // Make sure we write all the data
   //
   while (nLeft > 0)
   {
    ret = send(sock, &amp;szBuff[idx], nLeft, 0);
    if (ret == 0)
     break;
    else if (ret == SOCKET_ERROR)
    {
     printf("send() failed: %d\n",
      WSAGetLastError());
     break;
    }
    nLeft -= ret;
    idx += ret;
   }
  }
 }
 return 0;
}

//
// Function: main
//
// Description:
// Main thread of execution. Initialize Winsock, parse the
// command line arguments, create the listening socket, bind
// to the local address, and wait for client connections.
//
int main(int argc, char** argv)
{
 WSADATA wsd;
 SOCKET sListen,
  sClient;
 int iAddrSize;
 HANDLE hThread;
 DWORD dwThreadId;
 struct sockaddr_in local,
  client;

 ValidateArgs(argc, argv);
 if (WSAStartup(MAKEWORD(2, 2), &amp;wsd) != 0)
 {
  printf("Failed to load Winsock!\n");
  return 1;
 }
 // Create our listening socket
 //
 sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
 if (sListen == SOCKET_ERROR)
 {
  printf("socket() failed: %d\n", WSAGetLastError());
  return 1;
 }
 // Select the local interface and bind to it
 //
 if (bInterface)
 {
  local.sin_addr.s_addr = inet_addr(szAddress);
  if (local.sin_addr.s_addr == INADDR_NONE)
   usage();
 }
 else
  local.sin_addr.s_addr = htonl(INADDR_ANY);
 local.sin_family = AF_INET;
 local.sin_port = htons(iPort);

 if (bind(sListen, (struct sockaddr*)&amp;local,
  sizeof(local)) == SOCKET_ERROR)
 {
  printf("bind() failed: %d\n", WSAGetLastError());
  return 1;
 }
 listen(sListen, 8);
 //
 // In a continous loop, wait for incoming clients. Once one
 // is detected, create a thread and pass the handle off to it.
 //
 while (1)
 {
  iAddrSize = sizeof(client);
  sClient = accept(sListen, (struct sockaddr*)&amp;client,
   &amp;iAddrSize);
  if (sClient == INVALID_SOCKET)
  {
   printf("accept() failed: %d\n", WSAGetLastError());
   break;
  }
  printf("Accepted client: %s:%d\n",
   inet_ntoa(client.sin_addr), ntohs(client.sin_port));

  hThread = CreateThread(NULL, 0, ClientThread,
   (LPVOID)sClient, 0, &amp;dwThreadId);
  if (hThread == NULL)
  {
   printf("CreateThread() failed: %d\n", GetLastError());
   break;
  }
  CloseHandle(hThread);
 }
 closesocket(sListen);

 WSACleanup();
 return 0;
}
M. Saqib: Saqib is Master-level Senior Software Engineer with over 14 years of experience in designing and developing large-scale software and web applications. He has more than eight years experience of leading software development teams. Saqib provides consultancy to develop software systems and web services for Fortune 500 companies. He has hands-on experience in C/C++ Java, JavaScript, PHP and .NET Technologies. Saqib owns and write contents on mycplus.com since 2004.
Related Post