Introduction to Socket Programming

Theoretically Socket is an interface between an application process and transport layer. The application process can send/receive messages to/from another application process (local or remote)via a socket.

In Unix technically a Socket is a file descriptor – an integer associated with an open file.

A socket address is the combination of an IP address (the location of the computer) and a port (which is mapped to the application program process) into a single identity .

An Internet socket is characterized by a unique combination of the following:

  • Protocol: A transport protocol (e.g., TCP, UDP), raw IP, or others. TCP port 53 and UDP port 53 are different, distinct sockets.
  • Local socket address: Local IP address and port number
  • Remote socket address: Only for established TCP sockets. As discussed in the Client-Server section below, this is necessary since a TCP server may serve several clients concurrently. The server creates one socket for each client, and these sockets share the same local socket address.

Struct sockaddr_in {

short int sin_family; // set to AF_INET

unsigned short int sin_port; // Port number

struct in_addr sin_addr; // Internet address

unsigned char sin_zero[8]; //set to all zeros

};

struct in_addr {

unsigned long s_addr; // that’s a 32­bit long, or 4 bytes

};

OS and Application that created Socket refer Socket by an unique Socket Identifier/Number.

Server : Computer processes that provide application services. It create Socket(in listening State) on start up.

Client : Any Program(local or remote) which want to use Application services provided by server. Client send request to listening socket of Server.

Two Important Types of Sockets are

Stream Sockets

  • Connection oriented Sockets used in TCP.
  • May serve several clients concurrently, by creating a child process for each client and establishing a TCP connection between the child process and the client.
  • Unique dedicated sockets are created for each connection.
  • Each socket is identified by both local and remote IP address and port.

Datagram Sockets

  • Connectionless Sockets used in UDP.
  • No child process is created for multiple clients.
  • Single Socket serve all the clients.
  • Socket is identified by local port no. and Ip address.

Sockets are usually implemented by an API library such as Berkeley sockets.

socket() creates a new socket of a certain socket type, identified by an integer number, and allocates system resources to it.

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

  • domain should be set to PF_INET (PF_INET is protocol family, AF_INET is Address family)
  • type can be SOCK_STREAM or SOCK_DGRAM(for TCP/UDP)
  • set protocol to 0 to have socket choose the correct protocol based on type
  • socket() returns a socket descriptor for use in later system calls or -1 on error

bind() is typically used on the server side, and associates a socket with a socket address structure, i.e. a specified local port number and IP address.

int bind(int sockfd, struct sockaddr *my_addr, int addrlen)

  • sockfd is the socket descriptor returned by socket()
  • my_addr is pointer to struct sockaddr that contains information about your IP address and port
  • addrlen is set to sizeof(struct sockaddr)
  • returns -1 on error
  • my_addr.sin_port = 0; //choose an unused port at random
  • my_addr.sin_addr.s_addr = INADDR_ANY; //use my IP adr

listen() is used on the server side, and causes a bound TCP socket to enter listening state.

int listen(int sockfd, int backlog);

  • sockfd is the socket file descriptor returned by socket()
  • backlog is the number of connections allowed on
  • the incoming queue
  • listen() returns -1 on error
  • Need to call bind() before you can listen()

connect() is used on the client side, and assigns a free local port number to a socket. In case of a TCP socket, it causes an attempt to establish a new TCP connection.

int connect(int sockfd, struct sockaddr *serv_addr, int addrlen)

  • sockfd is the socket descriptor returned by socket()
  • serv_addr is pointer to struct sockaddr that
  • contains information on destination IP address and port
  • addrlen is set to sizeof(struct sockaddr)
  • returns -1 on error

accept() is used on the server side. It accepts a received incoming attempt to create a new TCP connection from the remote client, and creates a new socket associated with the socket address pair of this connection.

int accept(int sockfd, void *addr, int *addrlen);

  • sockfd is the listening socket descriptor
  • information about incoming connection is stored in
  • addr which is a pointer to a local struct sockaddr_in
  • addrlen is set to sizeof(struct sockaddr_in)
  • accept returns a new socket file descriptor to use
  • for this accepted connection and -1 on error

send() and recv(), or write() and read(), or recvfrom() and sendto(), are used for sending and receiving data to/from a remote socket.

int send(int sockfd, const void *msg, int len, int flags);

  • sockfd is the socket descriptor you want to send data to (returned by socket() or got from accept())
  • msg is a pointer to the data you want to send
  • len is the length of that data in bytes
  • set flags to 0 for now
  • sent() returns the number of bytes actually sent (may
  • be less than the number you told it to send) or -1 on error

int recv(int sockfd, void *buf, int len, int flags);

  • sockfd is the socket descriptor to read from
  • buf is the buffer to read the information into
  • len is the maximum length of the buffer
  • set flags to 0 for now
  • recv() returns the number of bytes actually read into the buffer or -1 on error
  • If recv() returns 0, the remote side has closed connection on you

close() causes the system to release resources allocated to a socket. In case of TCP, the connection is terminated.

int close(int sockfd);

  • Closes connection corresponding to the socket descriptor and frees the socket descriptor
  • Will prevent any more sends and recvs


gethostbyname() and gethostbyaddr() are used to resolve host names and addresses.

select() is used to prune a provided list of sockets for those that are ready to read, ready to write or have errors


poll() is used to check on the state of a socket. The socket can be tested to see if can be written to, read from or has errors.

    Sample Server File

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <errno.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <sys/wait.h>
    #include <signal.h>

    /* the port users will be connecting to */
    #define MYPORT 3490

    /* how many pending connections queue will hold */
    #define BACKLOG 10

    void sigchld_handler(int s)
    {
    while(wait(NULL) > 0);
    }
    int main(int argc, char *argv[ ])
    {

    /* listen on sock_fd, new connection on new_fd */

    int sockfd, new_fd;

    /* my address information */

    struct sockaddr_in my_addr;

    /* connector’s address information */

    struct sockaddr_in their_addr;

    int sin_size;

    struct sigaction sa;

    int yes = 1;

    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)  {

    perror(“Server-socket() error lol!”);
    exit(1);
    } else {

    printf(“Server-socket() sockfd is OK…\n”);
    }

    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)

    {

    perror(“Server-setsockopt() error lol!”);

    exit(1);

    } else{
    printf(“Server-setsockopt is OK…\n”);
    }

    /* host byte order */

    my_addr.sin_family = AF_INET;

    /* short, network byte order */

    my_addr.sin_port = htons(MYPORT);

    /* automatically fill with my IP */

    my_addr.sin_addr.s_addr = INADDR_ANY;

    //convert binary ip to string we use inet_ntoa
    printf(“Server-Using %s and port %d…\n”, inet_ntoa(my_addr.sin_addr), MYPORT);

    /* zero the rest of the struct */

    memset(&(my_addr.sin_zero), ”, 8);

    if(bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1)

    {

    perror(“Server-bind() error”);

    exit(1);

    }

    else

    printf(“Server-bind() is OK…\n”);

    if(listen(sockfd, BACKLOG) == -1)

    {

    perror(“Server-listen() error”);

    exit(1);

    }

    printf(“Server-listen() is OK…Listening…\n”);

    /* clean all the dead processes */

    sa.sa_handler = sigchld_handler;

    sigemptyset(&sa.sa_mask);

    sa.sa_flags = SA_RESTART;

    if(sigaction(SIGCHLD, &sa, NULL) == -1)

    {

    perror(“Server-sigaction() error”);

    exit(1);

    }

    else

    printf(“Server-sigaction() is OK…\n”);

    /* accept() loop */

    while(1) {

    sin_size = sizeof(struct sockaddr_in);

    if((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) {

    perror(“Server-accept() error”);

    continue;
    }   else {

    printf(“Server-accept() is OK…\n”);
    }

    printf(“Server-new socket, new_fd is OK…\n”);

    printf(“Server: Got connection from %s\n”, inet_ntoa(their_addr.sin_addr));

    /* this is the child process */

    if(!fork()) {

    /* child doesn’t need the listener */

    close(sockfd);

    if(send(new_fd, “This is a test string from server!\n”, 37, 0) == -1)

    perror(“Server-send() error lol!”);

    close(new_fd);

    exit(0);

    }

    else

    printf(“Server-send is OK…!\n”);

    /* parent doesn’t need this*/

    close(new_fd);

    printf(“Server-new socket, new_fd closed successfully…\n”);

    }

    return 0;

    }

    Sample Client File

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <errno.h>
    #include <string.h>
    #include <netdb.h>
    #include <sys/types.h>
    #include <netinet/in.h>
    #include <sys/socket.h>
    // the port client will be connecting to
    #define PORT 3490
    // max number of bytes we can get at once
    #define MAXDATASIZE 300

    int main(int argc, char *argv[])
    {

    int sockfd, numbytes;

    char buf[MAXDATASIZE];

    struct hostent *he;

    // connector’s address information

    struct sockaddr_in their_addr;

    // if no command line argument supplied

    if(argc != 2) {

    fprintf(stderr, “Client-Usage: %s the_client_hostname\n”, argv[0]);

    // just exit

    exit(1);

    }

    // get the host info

    if((he=gethostbyname(argv[1])) == NULL) {

    perror(“gethostbyname()”);

    exit(1);

    } else {

    printf(“Client-The remote host is: %s\n”, argv[1]);
    }

    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {

    perror(“socket()”);

    exit(1);

    } else {

    printf(“Client-The socket() sockfd is OK…\n”);

    }

    // host byte order

    their_addr.sin_family = AF_INET;

    // short, network byte order

    printf(“Server-Using %s and port %d…\n”, argv[1], PORT);

    their_addr.sin_port = htons(PORT);

    their_addr.sin_addr = *((struct in_addr *)he->h_addr);

    // zero the rest of the struct

    memset(&(their_addr.sin_zero), ”, 8);

    if(connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1)

    {

    perror(“connect()”);

    exit(1);

    }  else {

    printf(“Client-The connect() is OK…\n”);
    }

    if((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) {

    perror(“recv()”);

    exit(1);

    } else {

    printf(“Client-The recv() is OK…\n”);

    }

    buf[numbytes] = ”;

    printf(“Client-Received: %s”, buf);

    printf(“Client-Closing sockfd\n”);

    close(sockfd);

    return 0;

    }

    2 Responses to “Introduction to Socket Programming”

    1. surabhi Says:

      hey…did this socket code will work well for windows as well??i think for socket programming in windows we have to replace socket,h with winsock.h…. n 1 more query….well all the libraries included in the code r already present or they r to be included externally??

      • is0dvil Says:

        This code is using Berkeley Sockets not winsocks hence will not work in windows but some changes will make it work. If u are using GCC compiler then there is no need to install any libraries.

    Leave a comment