Originally Published: Tuesday, 30 November 1999 Author: Daniel Drown
Published to: develop_articles_tutorials/Development Tutorials Page: 1/1 - [Printable]

A Simple Internet Client Application

Daniel Drown shows how to open a connection to a network services. The following article requires basic C knowledge, and file I/O experience.

   Page 1 of 1  

Simple Internet client program - by Dan Drown

Required programming experience: compiling a program, basic C experience, file I/O experience.

Summary: An introduction to opening a connection to a network service.

Functions used:
socket(2) - create an endpoint for communication
connect(2) - initiate a connection on a socket
read(2) - read from a file descriptor
write(2) - write to a file descriptor
perror(3) - print a system error message
gethostbyname(3) - get the IP for a host
herror(3) - print a resolver error message (marked as obsolete???)
exit(3) - cause normal program termination
memcpy(3) - copy a memory area
htons(3) - convert a short integer from host byte order to network byte order.
close(2) - closes a file descriptor

see also:
ip(4)

/* Simple Internet client program - by Dan Drown <abob@linux.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* LINUX.COM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include <sys/types.h>  /* for socket,connect */
#include <sys/socket.h> /* for socket,connect */
#include <netinet/in.h> /* for htons */
#include <netdb.h>      /* for gethostbyname */
#include <string.h>     /* for memcpy */
#include <stdio.h>      /* for perror */
#include <stdlib.h>     /* for exit */
#include <unistd.h>     /* for read,write */

void build_inet_addr(struct sockaddr_in *addr, const char *hostname, unsigned short int port);
int connect_inet_addr(const char *hostname, unsigned short int port);

int main()
{
  int socket_descriptor, returnval;
  char str[80];

  socket_descriptor=connect_inet_addr("localhost", 80);

  strcpy(str, "HEAD / HTTP/1.0\r\n\r\n");

  returnval = write(socket_descriptor, str, strlen(str));
  if(returnval < 0)
  {
    /* write returns -1 on error */
    perror("write(..) error");
    exit(1);
  }

  if(returnval < strlen(str))
  {
    /* I'm not dealing with this error, regular programs should. */
    fprintf(stderr, "the write was short\n");
    exit(1);
  }

  while((returnval = read(socket_descriptor, str, 80)) > 0)
    /* write everything to stdout. */
    write(STDOUT_FILENO, str, returnval);

  /* it will be closed anyway when we exit */
  close(socket_descriptor);

  /* just to be pedantic... */
  return;
}

/* IN: hostname, port
 * OUT: socket descriptor
 * connects to the hostname:port specified. upon error, it prints a message
 * and calls exit(2).
 */

int connect_inet_addr(const char *hostname, unsigned short int port)
{
  int inet_socket; /* socket descriptor */
  struct sockaddr_in inet_address; /* IP/port of the remote host to connect to */

  build_inet_addr(&inet_address, hostname, port);

  /* socket(domain, type, protocol) */
  inet_socket = socket(PF_INET, SOCK_STREAM, 0);
  /* domain is PF_INET(internet/IPv4 domain) *
   * type is SOCK_STREAM(tcp) *
   * protocol is 0(only one SOCK_STREAM type in the PF_INET domain
   */


  if (inet_socket < 0)
  {
    /* socket returns -1 on error */
    perror("socket(PF_INET, SOCK_STREAM, 0) error");
    exit(2);
  }

  /* connect(sockfd, serv_addr, addrlen) */
  if(connect(inet_socket, (struct sockaddr *)&inet_address, sizeof(struct sockaddr_in)) < 0)
  {
    /* connect returns -1 on error */
    perror("connect(...) error");
    exit(2);
  }

  return inet_socket;
}

/* IN: hostname, port
 * OUT: struct sockaddr_in is setup
 * sets up the sockaddr_in structure. upon error, it prints a message and
 * calls exit(3).
 */

void build_inet_addr(struct sockaddr_in *addr, const char *hostname, unsigned short int port)
{
  struct hostent *host_entry;

  /* gethostbyname(name) */
  host_entry = gethostbyname(hostname);

  if(host_entry == NULL)
  {
    /* gethostbyname returns NULL on error */
    herror("gethostbyname failed");
    exit(3);
  }

  /* memcpy(dest, src, length) */
  memcpy(&addr->sin_addr.s_addr, host_entry->h_addr_list[0], host_entry->h_length);
  /* copy the address to the sockaddr_in struct. */

  /* set the family type (PF_INET) */
  addr->sin_family = host_entry->h_addrtype;

  /* addr->sin_port = port won't work because they are different byte
   * orders
   */

  addr->sin_port = htons(port);

  /* just to be pedantic... */
  return;
}




   Page 1 of 1