Last Updated:

Socket Programming using C ++ / Linux

Sockets are used to provide network communications. A socket is the endpoint of network communications. Each socket in use has a type and an associated process. Sockets exist within communication domains. Domains are abstractions that imply a specific addressing structure and a set of protocols that define different types of sockets within a domain. Examples of communication domains can be: UNIX domain, Internet domain, etc.

In an Internet domain, a socket is a combination of an IP address and a port number that uniquely identifies a single network process throughout the global Internet. Two sockets, one for the receiving host and the other for the sending host, define the connection for communication-oriented protocols such as TCP.

  • Creating a Socket
  • Binding to local names
  • Link
  • Data transfer
  • Closing sockets
  • Example of a function for establishing a WWW connection

Creating a Socket

The socket system call is used to create the socket.

s = socket(domain, type, protocol);

This call is based on information about the communication domain and socket type. To use the features of the Internet, the parameter values must be as follows:

  • communication domain - AF_INET (Internet protocols).
  • type of the socket - SOCK_STREAM; This type provides a consistent, reliable, two-way oriented flow of bytes.

A socket with a stream type was mentioned above. A brief description of the other types of sockets is given below:

  • Datagram socket - supports two-way data streaming. It is not guaranteed that this stream will be consistent, reliable, and that the data will not be duplicated. An important characteristic of this socket is that the boundaries of the data record are predefined.
  • Raw socket - provides user access to downstream communication protocols that support socket abstractions. Such sockets are usually datagram-oriented.

The socket function creates an endpoint for communications and returns a file handle that references the socket, or -1 in the event of an error. This handle is then used to establish a connection.

To create a stream socket with TCP that provides communication support, the call to the socket function must be as follows:

s = socket(AF_INET, SOCK_STREAM, 0);

Binding to local names

The socket is created without a name. Until a name is associated with a socket, remote processes cannot reference it and therefore no messages can be received on the socket. Communication processes are used for these purposes by associations. In an Internet domain, an association consists of a local and remote address, and a local and remote port. In most domains, the association must be unique.

In an Internet domain, binding a socket and a name can be quite complex, but fortunately, it is usually not necessary to specifically bind the address and port number to the socket, since the connect and send functions will automatically associate this socket with the appropriate address if this was not done before they were called.

To bind the socket to the address and port number, use the bind system call:

bind(s, name, namelen);

A binding name is a string of variable-length bytes that is interpreted by a supported protocol. Interpretation may vary across communication domains.

Link

On the client side, the connection is established using the standard connect function:

error = connect(s, serveraddr, serveraddrlen);

which initiates communication on the socket using the socket handle s and information from the serveraddr structure, which has a type of sockaddr_in that contains the address of the server and the port number to which to link. If the socket has not been associated with an address, connect will automatically call the bind system function.

Connect returns 0 if the call was successful. A return value of -1 indicates that an error occurred during the linking process. If the function call is successful, the process can work with the socket handle using the read and write functions, and close the channel using the close function.

On the server side, the communication process is more complicated. When a server wants to offer one of its services, it associates a socket with a well-known address associated with that service and passively listens to that socket. For these purposes, the listen system call is used:

error = listen(s, qlength);

where s is the socket handle and qlength is the maximum number of communication requests that can queue while waiting to be processed by the server. this number may be limited by the features of the system.

When the server receives a request from a client and decides to establish a connection, it creates a new socket and associates it with an association equivalent to a 'listening socket'. For an Internet domain, this means the same port number. For this purpose, the accept system call is used:

newsock = accept(s, clientaddr, clientaddrlen);

The socket associated by the client and the socket that was returned by the accept function are used to establish communication between the server and the client.

Data transfer

When a connection is established, the data transfer process can begin with the help of various functions. If there is a connection, the user can send and receive messages using the read and write functions:

write(s, buf, sizeof(buf)); read(s, buf, sizeof(buf));

The send and recv calls are almost identical to read and write, except that a flag argument is added.

send(s, buf, sizeof(buf), flags); recv(s, buf, sizeof(buf), flags);

One or more flags can be specified using non-zero values, such as the following:

  • MSG_OOB - Send/receive data specific to stream sockets.
  • MSG_PEEK - View data without reading. when specified in recv, any present data is returned to the user, but the data itself remains as "unread". The next read or recv called on this socket will return the data read last time.
  • MSG_DONTROUTE is to send data without routing packets. (Used only by processes that manage routing tables.)

Closing sockets

When the communicating modules decide to stop transmitting data and close the communication session, they exchange a three-way handshake with segments containing the set bit "There is no more data from the sender" (this bit is also called the FIN bit).

If the socket is no longer in use, the process can close it using the close function, calling it with the appropriate socket handle:

close(s);

If the data has been associated with a socket that promises delivery (a stream socket), the system will attempt to transfer that data. However, after a fairly long period of time, if the data is still not delivered, it will be discarded. If a user process wishes to stop any data transfer, it can do so by calling shutdown on the socket to close it. Calling shutdown causes all queued data to be dropped "instantly". The format of the call is as follows:

shutdown(s, how);

where how has one of the following values:

  • 0 - if the user no longer wants to read the data
  • 1 - if the data will no longer be sent
  • 2 - if the data will neither be sent nor received

Example of a function for establishing a WWW connection

/*

  MakeConnection

  Function allocates a socket and estabishes a connection
  with remote host. Default port number 80.

  Input : WWW server name (with port number, if it is not 80)
  Output : file descriptor on success
              -1 on error

*/
int MakeConnection(unsigned char* ServerName){
  int s;
  struct sockaddr_in ssin;
  struct hostent* hp;
  int PortNum;
  unsigned char strHlp[STRNGLEN], *pch;

  /* use default port number - 80 or specific number from the
     server name */
  strcpy(strHlp,ServerName);
  pch = strchr(strHlp,':');
  if(pch==NULL){
    PortNum = 80;
  }else{
    pch[0] = '';
    pch++;
    PortNum = atoi(pch);
    if(PortNum==0){
      PortNum = 80;
    }
  }

  /* get host by name - resolve host name into IP address */
  if( (hp=gethostbyname(strHlp)) == NULL  )
  {
     return -1;
  }

  bzero(&ssin, sizeof(ssin));
  bcopy(hp->h_addr, &ssin.sin_addr, hp->h_length);
  ssin.sin_family = hp->h_addrtype;
  ssin.sin_port = htons(PortNum);

  /* allocate a socket */
  if((s=socket(AF_INET, SOCK_STREAM, 0))==-1)
  {
     return -1;
  }

  /* make a connection */
  if(connect(s, &ssin, sizeof(ssin), 0)==-1){

     return -1;
  }

  return s; /* socket descriptor */
}