Socket Programming in C/C++

Info Programmer Blog

Introduction :

Sockets are a protocol independent method of creating a connection between processes. Sockets can be either

  • connection based or connectionless: Is a connection established before communication or does each packet
    describe the destination?
  • packet based or streams based: Are there message boundaries or is it one stream?
  • reliable or unreliable. Can messages be lost, duplicated, reordered, or corrupted?

Socket characteristics :

Socket are characterized by their domain, type and transport protocol. Common domains are:

  • AF_UNIX: address format is UNIX pathname
  • AF_INET: address format is host and port number

Common types are:

virtual circuit: received in order transmitted and reliably datagram: arbitrary order, unreliable Each socket type has one or more protocols. Ex:

  • TCP/IP (virtual circuits)
  • UDP (datagram)

Use of sockets:

  • Connection–based sockets communicate client-server: theserver waits for a connection from the client
  • Connectionless sockets are peer-to-peer: each process is symmetric.

Socket APIs

  • socket: creates a socket of a given domain, type, protocol
  • bind: assigns a name to the socket
  • listen: specifies the number of pending connections thatcan be queued for a server socket.
  • accept: server accepts a connection request from a client
  • connect: client requests a connection request to a server
  • send, sendto: write to connection (speak)
  • recv, recvfrom: read from connection (listen)
  • shutdown: end the call

Connection-based communication : 

Server performs the following actions

  • socket: create the socket
  • bind: give the address of the socket on the server
  • listen: specifies the maximum number of connection requests that can be pending for this process
  • accept: establish the connection with a specific client
  • send,recv: stream-based equivalents of read and write(repeated)
  • shutdown: end reading or writing
  • close: release kernel data structures

TCP client :

Client performs the following actions

  • socket: create the socket
  • connect: connect to a server
  • send,recv: (repeated)
  • shutdown
  • close

Socket API : 

#include <sys/types.h>

#include <sys/socket.h>

int  socket ( int domain , int type , int protocol ) ;

Returns a file descriptor (called a socket ID) if successful, -1

otherwise. Note that the socket returns a socket descriptor which

is the same as a file descriptor.

The domain is AF_INET.

The type argument can be:

  • SOCK_STREAM: Establishes a virtual circuit for stream
  • SOCK_DGRAM: Establishes a datagram for communication
  • SOCK_SEQPACKET: Establishes a reliable, connection based,

two way communication with maximum message size. (This is not available on most machines.) protocol is usually zero, so that type defines the connection within domain.

Bind API:

#include <sys / types.h>

#include <sys / socket.h>

int bind ( int sid , struct sockaddr∗ addrPtr , int len );

Where

  • sid: is the socket id
  • addrPtr: is a pointer to the address family dependent address structure
  • len: is the size of *addrPtrAssociates a socket id with an address to which other processes can connect. In internet protocol the address is [IP Number, portNumber]

sockaddr:

The sockaddr structure varies depending on the protocol selected. Except for the sin*_family parameter, sockaddr contents are expressed in network byte order.

Winsock functions using sockaddr are not strictly interpreted to be pointers to a sockaddr structure. The structure is interpreted differently in the context of different address families. The only requirements are that the first u_short is the address family and the total size of the memory buffer in bytes is namelen.

The SOCKADDR_STORAGE structure also stores socket address information and the structure is sufficiently large to store IPv4 or IPv6 address information. The use of the SOCKADDR_STORAGE structure promotes protocol-family and protocol-version independence, and simplifies development. It is recommended that the SOCKADDR_STORAGE structure be used in place of the sockaddr structure. The SOCKADDR_STORAGE structure is supported on Windows Server 2003 and later.

The sockaddr structure and sockaddr_in structures below are used with IPv4. Other protocols use similar structures.

Prototypes :

#include <netinet/in.h>
// All pointers to socket address structures are often cast to pointers
// to this type before use in various functions and system calls:
struct sockaddr 
{
    unsigned short    sa_family;    // address family, AF_xxx
    char              sa_data[14];  // 14 bytes of protocol address
};

// IPv4 AF_INET sockets:
struct sockaddr_in 
{
    short            sin_family;   // e.g. AF_INET, AF_INET6
    unsigned short   sin_port;     // e.g. htons(3490)
    struct in_addr   sin_addr;     // see struct in_addr, below
    char             sin_zero[8];  // zero this if you want to
};

struct in_addr 
{
    unsigned long s_addr;          // load with inet_pton()
};

// IPv6 AF_INET6 sockets:
struct sockaddr_in6 
{
    u_int16_t       sin6_family;   // address family, AF_INET6
    u_int16_t       sin6_port;     // port number, Network Byte Order
    u_int32_t       sin6_flowinfo; // IPv6 flow information
    struct in6_addr sin6_addr;     // IPv6 address
    u_int32_t       sin6_scope_id; // Scope ID
};

struct in6_addr 
{
    unsigned char   s6_addr[16];   // load with inet_pton()
};

// General socket address holding structure, big enough to hold either
// struct sockaddr_in or struct sockaddr_in6 data:

struct sockaddr_storage 
{
    sa_family_t  ss_family;     // address famil
    // all this is padding, implementation specific, ignore it:
    char      __ss_pad1[_SS_PAD1SIZE];
    int64_t   __ss_align;
    char      __ss_pad2[_SS_PAD2SIZE];
};

Listen API:

#include <sys / types.h>

#include <sys / socket.h>

int listen ( int sid , int size );

Where size it the number of pending connection requests allowed (typically limited by Unix kernels to 5).

Returns the 0 on success, or -1 if failure.

Accept API :

#include <sys / types.h>

#include <sys / socket.h>

int accept ( int sid , struct sockaddr ∗ addrPtr , int ∗ lenPtr );

Returns the socket Id and address of client connecting to socket. if lenPtr or addrPtr equal zero, no address structure is returned. lenPtr is the maximum size of address structure that can be called, returns the actual value. Waits for an incoming request, and when received creates a socket for it.

Send API :

#include <sys / types.h>

#include <sys / socket.h>

int send ( int sid , const char ∗ buffer Ptr ,int len , int flag );

Send a message. Returns the number of bytes sent or -1 if failure.

(Must be a bound socket).

flag is either

  • 0: default
  • MSG_OOB: Out-of-band high priority communication

Recv API :

#include <sys / types.h>

#include <sys / socket.h>

int recv ( int sid , char ∗bufferPtr ,int len , int flags );

Receive up to len bytes in bufferPtr. Returns the number of bytes received or -1 on failure.

flags can be either

0: default

MSG_OOB: out-of-bound message

MSG_PEEK: look at message without removing

Shutdown API :

#include <sys / types.h>

#include <sys / socket.h>

int shutdown ( int sid , int how );

Disables sending (how=1 or how=2) or receiving (how=0 or how=2). Returns -1 on failure. acts as a partial close.

Connect API :

this is the first of the client calls

#include <sys / types.h>

#include <sys / sock et.h>

int connect ( int sid , struct sockaddr ∗ addrPtr , int len );

Specifies the destination to form a connection with (addrPtr), and returns a 0 if successful, -1 otherwise.

Denoting Connections : 

Note that a connection is denoted by a 5-tuple:

  • from IP
  • from port
  • protocol
  • to IP
  • to port

So that multiple connections can share the same IP and port.

Port usage :

Note that the initiator of communications needs a fixed port to target communications. This means that some ports must be reserved for these “well known” ports.

Port usage:

  • 0-1023: These ports can only be binded to by root
  • 1024-5000: well known ports
  • 5001-64K-1: ephemeral ports

APIs for managing names and IP addresses :

We next consider a number of auxiliary APIs:

  • The hostent structure: describes IP, hostname pairs
  • gethostbyname: hostent of a specified machine
  • htons, htonl, ntohs, ntohl: byte ordering
  • inet_pton, inet_ntop: conversion of IP numbers between presentation and strings

gethostname API:

NAME
gethostname, sethostname – get/set hostname

SYNOPSIS
#include <unistd.h>

int gethostname(char *name, size_t len);
int sethostname(const char *name, size_t len);

RETURN VALUE
On success, zero is returned. On error, -1 is returned, and errno is
set appropriately.

Network byte ordering : 

Network ordering in big endian. (Sparc is big endian, Intel is little endian).

NAME
htonl, htons, ntohl, ntohs – convert values between host and network byte order

SYNOPSIS
#include <arpa/inet.h>

uint32_t htonl(uint32_t hostlong);

uint16_t htons(uint16_t hostshort);

uint32_t ntohl(uint32_t netlong);

uint16_t ntohs(uint16_t netshort);

DESCRIPTION
The htonl() function converts the unsigned integer hostlong from host byte order to network byte order.

The htons() function converts the unsigned short integer hostshort from host byte order to network byte order.

The ntohl() function converts the unsigned integer netlong from network byte order to host byte order.

The ntohs() function converts the unsigned short integer netshort from network byte order to host byte order.

IP Number translation :

IP address strings to 32 bit number

In what follows, ’p’ stands for presentation.

Hence, these routines translate between the address as a string and the address as the number.

Hence, we have 4 representations:

  • IP number in host order
  • IP number in network order
  • Presentation (eg. dotted decimal)
  • Fully qualified domain name

Only the last needs an outside lookup to convert to one of the other formats.

inet_pton API :

NAME
inet_pton – convert IPv4 and IPv6 addresses from text to binary form

SYNOPSIS
#include <arpa/inet.h>

int inet_pton(int af, const char *src, void *dst);

DESCRIPTION
This function converts the character string src into a network address structure in the af address family, then copies the network address structure to dst. The af argument must be either AF_INET or AF_INET6.

inet_ntop API :

NAME
inet_ntop – convert IPv4 and IPv6 addresses from binary to text form

SYNOPSIS
#include <arpa/inet.h>

const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);

DESCRIPTION
This function converts the network address structure src in the af address family into a character string. The resulting string is
copied to the buffer pointed to by dst, which must be a non-null pointer. The caller specifies the number of bytes available in
this buffer in the argument size.

Example: TCP/IP Server Code:
Without error checking.

#include<stdio.h>
#include<netinet/in.h>
#include<string.h>
main(int argc,char **argv)
{
int sfd,newsfd;
struct sockaddr_in server,client;
char buf[128];
sfd=socket(PF_INET,SOCK_STREAM,0);
if(sfd<0)
{ perror(“socket”);
return;
}
server.sin_family=PF_INET;
server.sin_port=htons(atoi(argv[1]));
server.sin_addr.s_addr=inet_addr(argv[2]);

if(bind(sfd,(struct sockaddr*)&server,sizeof(server))==0)
printf(“bind:sucesses\n”);
else
printf(“bind fail…\n”);

listen(sfd,1);
int len;
len=sizeof(client);
printf(“waiting for connection…\n”);
newsfd=accept(sfd,(struct sockaddr*)&client,&len);

bzero(buf,128);
printf(“connected…..\n”);
read(newsfd,buf,sizeof(buf));
printf(“in server:%s\n”,buf);
}

Example: TCP/IP Client code :

#include<stdio.h>
#include<netinet/in.h>
#include<string.h>
main(int argc,char **argv)
{
int sfd;
struct sockaddr_in client;
char buf[128];
sfd=socket(PF_INET,SOCK_STREAM,0);
if(sfd<0)
{
perror(“socket”);
return;
}

client.sin_family=PF_INET;
client.sin_port=htons(atoi(argv[1]));
client.sin_addr.s_addr=inet_addr(argv[2]);

connect(sfd,(struct sockaddr*)&client,sizeof(client));
perror(“connect”);
bzero(buf,128);
printf(“Enter the data…..\n”);
scanf(“%s”,buf);
write(sfd,buf,sizeof(buf));
}

Connectionless communication :

Communication is symmetric (peer-to-peer)

  • socket
  • bind: bind is optional for initiator
  • sendto, recvfrom (repeated)
  • shutdown
  • close

UDP variations :

It is not necessary for both sockets to bind

  • The receiver gets the address of the sender

It is possible for a UDP socket to connect

  • In this case, send/recv (or write/read) must be used instead of sendto/recvfrom.
  • Asynchronous errors can be returned (using ICMP)

Sendto API : for connectionless protocols

NAME
send, sendto, sendmsg – send a message on a socket

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

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);

ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);

DESCRIPTION
The system calls send(), sendto(), and sendmsg() are used to transmit a message to another socket.

recvfrom API :

NAME
recv, recvfrom, recvmsg – receive a message from a socket

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

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);

DESCRIPTION
recvfrom() calls are used to receive messages from a socket. They may be used to receive data on both
connectionless and connection-oriented sockets. This page first describes common features of all three system calls, and then describes the differences between the calls.

Example: UDP—server

#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>
#include<string.h>
main()
{
int sfd,cfd,len;
char a[20];

struct sockaddr_in server,client;
sfd=socket(PF_INET,SOCK_DGRAM,0);
if(sfd<0)
{
perror(“socket”);
return;
}
server.sin_family=PF_INET;
server.sin_port=htons(3000);
server.sin_addr.s_addr=inet_addr(“0.0.0.0”);

if(bind(sfd,(struct sockaddr*)&server,sizeof(server))==0)
printf(“bind:sucess…\n”);
else
printf(“bind fail….\n”);
bzero(a,20);
len=sizeof(client);

printf(“waiting for connection…..\n”);

while(1)
{bzero(a,20);
recvfrom(sfd,a,20,0,(struct sockaddr*)&client,&len);
perror(“recvfrom”);
printf(“DATA RECEIVED = %s\n”,a);
}

}

Example: UDP—client

#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>
main()
{
int sfd;
char a[20];

struct sockaddr_in sin;

sfd=socket(PF_INET,SOCK_DGRAM,0);
perror(“socket”);
sin.sin_family=PF_INET;

sin.sin_port=htons(3000);

sin.sin_addr.s_addr=inet_addr(“127.0.0.1”);

while(1)
{

printf(“Enter data….\n”);
scanf(“%s”,a);
sendto(sfd,a,sizeof(a),0,(struct sockaddr*)&sin,sizeof(sin));
perror(“sendto”);

}
}

Read this also:

Difference Between Microprocessor And Microcontroller

Please follow and like us:

1 thought on “Socket Programming in C/C++

Leave a Reply