TCP / IP socket programming in C for applications

Contents

  Intro / Plug....................................A
  Getting Started ................................1   Opening Sockets ................................2
  Binding Sockets ................................3
  Connecting Sockets .............................4
  Accepting Sockets ..............................5
  Sending data ...................................6
  Receiving Data .................................7
  Closing a socket ...............................8

  The Applications
  pscan - simple tcp port scanner .................................. 9
  stcplog - simple tcp server log ................................. 10
  mtcplog - simple tcp server that will accept multiple clients ... 11
  mudplog - simple udp server that will accept multiple clients ... 12
  tcpcli - simple tcp client ...................................... 13

  usefull functions / My Network API: ............A
  Referance: .....................................B

  Thanks To:......................................C



.....

Intro / Plug

I wrote this tutorial because I program network applications regularly, and I prefer to use BSD style socket calls whenever possible. While there was a great deal of information available on the internet for someone who wants to learn to program sockets, I found that not too much of it focused specifically on the application level. My goal is to provide myself and others with a single source starting point, for programming nearly and transport level or higher network application

  This tutorial ( not quite yet finished ) was written by Matthew Fatheree matthewf@spyder-fonix.com . If you like it, love it, hate it, think it sucks, if you printed it out and then you used it as a bottom for your bird cage, or if you put salt on it and ate it... Please send questions, comments, and death threats to me.

All joking aside feedback and corrections would be great. Thanks...
~Matt Fatheree

http://www.spyder-fonix.com

.....

Getting Started

Extra Utilities

    Okay to start programming sockets it is assumed that you already have a compiler, and a working IP stack you can utilize.  Most of the code I've written here was written for Linux machines but it should be fairly portable to windows IP stack, using SOCKET in place of int for winsocks as well.
weather you are using Linux or windows I would highly recommend getting Ethereal, and Netcat. I use them constantly while doing network programming.
  Ethereal is an ethernet packet sniffer, it will allow you to see the data being transsmitted over the ethernet wire.
  netcat is a multi-function network utility, it can act as client or server, and log, redirect, and pipe input and output very easily.

<insert cheap plug here> check out my very own netcat information page

Header Files

  When programming sockets you will need to #include the following header files:

 #include <sys/types.h> /* basic system data types */
 #include <sys/socket.h> /* basic socket definitions */
 #include <sys/time.h> /* timeval{} for select() */
 #include <time.h> /* timespec{} for pselect() */
 #include <netinet/in.h> /* sockaddr_in{} and other Internet defns */
 #include <arpa/inet.h> /* inet(3) functions */
 #include <errno.h>
 #include <fcntl.h> /* for nonblocking, on windows don't use fnctl(), use ioctlsocket() */
 #include <netdb.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h> /* for S_xxx file mode constants */
 #include <unistd.h> /* this file is typically only for Linux *nix OS's */
 #include <sys/wait.h>
 #include <sys/un.h> /* for Unix domain sockets */
 #include <stdarg.h> /* for sdprintf */

Usefull Defines

  I have found it is useful to have the following things defined in some header file when doing socket programming :


/* Define bzero( ) as a macro if it's not in standard C library. */
#ifndef HAVE_BZERO
#define bzero( ptr, n )    memset( ptr, 0, n )
#endif


/* Following shortens all the type casts of pointer arguments */
#define SA       struct sockaddr
#define SA_in    struct sockaddr_in


#define min( a , b )    ( ( a ) < ( b ) ? ( a ) : ( b ) )
#define max( a , b )    ( ( a ) > ( b ) ? ( a ) : ( b ) )

Understanding TCP and UDP

TCP, and UDP are the two main types of sockets people use when programming applications.  TCP stands for transmission control protocol, while UDP stands for user datagram protocol. The main difference between TCP and UDP is TCP verifies that every packet sent gets recieved, and if data is missed, TCP will let you know, or retransmit it. UDP basically sends out a packet with an address and a port and hopes it gets there.  Despite the lack of ACKs and NAKs UDP is just about as reliable as TCP.

Understanding Clients and Servers

Weather you are using TCP or UDP, every network connection is going to have two parts, and every network program is going to be one of these two parts. Occasionally you will have network programs that do both.  The two types are Client and Server, also known as Active, and Passive, or Outgoing and Incomming.
there is no defacto standard to be sure for describing the two parts... but Client Server is used allot.
just for refrance.
Client = Active = Outgoing
Server = Passive = Incomming

heres is a basic run down on the application level and network level, of the different socket connections.

Client Communications

Application level
Network PC level
socket( );
  socket is called by the program.   This will set up a data structure for the operating system to use, to read and write, and control the socket
view the man page
*bind( );   With active ( client ) sockets you do not always need to call bind, but if you would like to designate a particular IP port to be used with the UDP socket you will need to fill in the struct sockaddr_in, and make a call to bind();,   bind is used to set the address and port number associated with a given socket
view the man page
connect( );   With UDP sockets you do not always need to call connect before sending, With TCP this connect call will make the OS preform what is known as "the TCP three part handshake".  This consists of the Client computer ( the computer that called connect ) sending a SYN packet, to the Server computer.   If all goes well the server computer will respond with an SYN,ACK packet, and then finally the Client computer sends a final ACK packet.  If all this works well connect( ) returns a posetive integer, and you will have a connected socket
view the man page
send( );, and
or recv( );, sendto( );, recvfrom( );
  UDP can use send( ), recv( ), sendto( ), recvfrom( ), read( ), and write( ) for passing data.   If you have used bind to bind a ipaddress and port, you will most likely want to just use recv for reading, and send for sending.   If you have not used bind on the UDP socket it may be nessary to use sendto, and recv, or recvfrom. When using TCP it is more common for applications to use send, and recv, allthough sendto, recvfrom, and read and write do work.
view the man page send
view the man page recv
close( );, shutdown( );   These functions will close the socket and deallocate any resources from the OS.
view the man page close
view the man page shutdown

Server Communications

Application level
Network PC level
socket( );
is called by the program
  This will set up a data structure for the operating system to use, to read and write, and control the socket
view the man page
*bind( );   In server applications it you will almost always see a call to bind( ). Bind is used to realte a local port number to a socket, therefore if you wanted to create a server that ran on a specific port, such as telnet, FTP, and HTTP, you will need to use bind in your sever application.
view the man page
*listen( );   The call to listen( ) is only needed in TCP applications, this will allow you to specify how many clients can connect to any given TCP port at one time.
view the man page listen
*accept( );   The call to accept( ) again , is only needed in TCP applications, this will allow you to preform the server side of the three way handshake when a client connects.  If accept is successfull it will return a new socket to you for reading and writting.
view the man page accept
send( );, and
or recv( );, sendto( );, recvfrom( );
  UDP can use send( ), recv( ), sendto( ), recvfrom( ), read( ), and write( ) for passing data.   If you have used bind to bind a ipaddress and port, you will most likely want to just use recv for reading, and send for sending.   If you have not used bind on the UDP socket it may be nessary to use sendto, and recv, or recvfrom.
view the man page send
view the man page recv
close( );, shutdown( );   These functions will close the socket and deallocate any resources from the OS.
view the man page close
view the man page shutdown

...
Blocking and non-blocking sockets
    Working with sockets is similar to working with linux files using stdio.
for sake of simplification lets say there are two working modes a TCP or UDP socket can be in. blocking or non blocking.
in blocking mode the program will halt unit the desires socket action is preformed. take the following code for example.

  /* sd is our socket file descriptor already open and listening attempting to accept a connection from a remote host */
  result = accept( sd, ( struct sockaddr *(NULL), NULL);



if sd was a blocking socket, the program would halt there until a remote client tried to connect or an error was recieved, with a non-blocking socket the call would immeidiately return allowing your program to continue execution, and result would be set to the value of E_WOULDBLOCK.

setting blocking or nonblocking mode
/* to set a socket into blocking mode use the following call */
fcntl( socket_fd, F_SETFL, 0);    /* last arg is zero, not the letter 'O' */

/* to set a socket into non-blocking mode use the following call */
fcntl( socket_fd, F_SETFL, O_NONBLOCK);    /* last arg is the letter 'O' then '_NONBLOCK' */


...

Opening sockets

Opening a socket is fairly trivial, below I have some code that will show you how to open a TCP, or UDP socket.

TCP Socket
#include <socket.h>    //  needed for socket( ) int tcp_sock; tcp_sock = socket( AF_INET, SOCK_STREAM, 0);    //  open a TCP socket
UDP Socket
#include <socket.h>    //  needed for socket( ) int udp_sock; udp_sock = socket( AF_INET, SOCK_DGRAM, 0);    //  open a UDP socket

  As you can see there is not much difference when opening a TCP socket or a UDP socket with the exception of passing the open call either SOCKSTREAM, for TCP, and SOCK_DGRAM for UDP.  WHen this call returns you will either get a negative return value which means an error has occured, or you will get the 'socket handle' or the file descriptor used to control the socket.   Allthough the socket is opened at this point, it does not have an associated TCP port, or IP address.

...

Binding Sockets

  For most people here is where things will start to get tricky. It is important to remember that for any given socket connection there are four things that make that connection possible. A Local Ip address, a Local port, a remote Ip address, and a Remote port.  Before you are ready to connect, or accept on your socket to anything you must first fill in a structure, that will tell the computer the correct values for these four parameters.  Bind is the call that ties a filled in structure to an IP address.

struct sockaddr_in, &
struct sockaddr

struct sockaddr_in

struct sockaddr_in {
	sa_family_t sin_family;
	struct in_addr sin_addr;
	unsigned short int sin_port;
}
This is the data type used to represent socket addresses in the Internet namespace. It has the following members:

sa_family_t sin_family
This identifies the address family or format of the socket address. You should store the value AF_INET in this member. See Socket Addresses.

struct in_addr sin_addr
This is the Internet address of the host machine. See Host Addresses, and Host Names, for how to get a value to store here.

unsigned short int sin_port
This is the port number. See Ports.
	 



struct sockaddr

struct sockaddr {
    sa_family_t   sa_family;       
    char          sa_data[];
}
sa_family_t sin_family
This identifies the address family.

char sa_data
This is the Internet address of the host machine. See Host Addresses, and Host Names, for how to get a value to store here.

    When Creating a Socket connection you will need to use one of the above structures to point to the IP address and port information that relates to each individual socket.
The code sample below will show you how to set up one of these structures, and bind it to a socket.


    int s;                    //  socket file descriptor 'handle'
    struct sockaddr_in ssfd;  //  socket structure
    int bindok;
	 
    s = socket(AF_INET, SOCK_STREAM, 0);  //  open the socket
	if( s < 0 ){
        printf("Could not open socket %d\n\r", s);
		return  s;
    }
    if( s ){
        memset( &ssfd, 0, sizeof( ssfd ) );   //  clear out our structure
        ssfd.sin_family = AF_INET;            //  Set Internet address Family
        ssfd.sin_addr.s_addr = htonl( NULL ); //  Client address will be filled 
                                              //  in automatically
        ssfd.sin_port = htons( 1313 );        //  This sets the TCP port number 
		                                      //to 1313
    }
    
    /*  note bind takes a pointer to a sockaddr 
        structures NOT sockaddr_in, you need to typecast */
    bindok = bind( s, ( struct sockaddr *)&ssfd, sizeof( ssfd ) ); //  call to bind 
    if( bindok < 0 ){
        printf("could not bind socket to file descriptor\n\r");
    }
    If all goes well the call to bind() will return a posetive integer, and that means you have a open socket that is locally bound. You should note that not all client applications bind() the socket before connecting to a remote host. But I think it is good practice as it allows you to specify the port from where the connection will start. Once you are at this point, it is time, to either connect to a remote host, or accept a connection from a remote host.


...

Connecting Sockets

  For most people binding, and connecting is where things will start to get tricky. It is important to remember that for any given socket connection there are four things that make that connection possible. A Local Ip address, a Local port, a remote Ip address, and a Remote port.  Many times on a connecting ( active ) socket, we can allow the OS to fill in our socket information for us. the code below shows how to make a connection to a remote host.

    int s;
    struct sockaddr_in servaddr;
	
    /* set up socket */
    if ( ( s = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 ){
        printf("socket failure\n\r"); 
        return s;
    }
    /* set up server address */
    memset( &servaddr, 0,  sizeof( servaddr ) );
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons( 1313 );      //  port 1313 again
    servaddr.sin_addr.s_addr = inet_addr("192.168.0.13");

    /* connect to server */
    if (connect( s, ( struct sockaddr * ) &servaddr, sizeof( servaddr ) ) < 0) {
        printf("\n\rconnect failure\n\r");
    }
    A succesfull call to connect() does not return a new socket file descriptor, which can be confusing for new programmers, rather connect() will connect the file descriptor you pass it, and if successfull, that socket can then be used when reading or writting. You should also note that connect(), like bind() takes a pointer to a structure of type sockaddr, not sockaddr_in !... you should typecast to remove compiler warnings.

...

Accepting Sockets

    If you are not opening a socket and making a connection there is a good chace you are using the socket for accepting a connection.  Acepting a connection really has two parts, on any socket that will eventually accept a connection before you can call accept you must call listen();
listen takes two parameters, the socket you would like to listen on, and the Maximum number of sockets that you will accept on that socket at any given time. for example a call like this
  listen( socket, 5);
would tell the OS that I can only allow five client sockets to connect at any one given time. the code example below illustrates how to accept a socket connection.
    int s;                //  server socket file descriptor 'handle'
    int c;                //  client socket file descriptor 'handle'
    struct sockaddr_in ssfd;  //  server socket structure
    struct sockaddr_in ccfd;  //  client socket structure
    int bindok;
	 
    s = socket( AF_INET, SOCK_STREAM, 0 );  //  open the socket
    if( s < 0 ){
        printf( "Could not open socket %d\n\r", s );
        return ( s );
    }
    if( s ){
        memset( &ssfd, 0, sizeof( ssfd ) );   //  clear out our structure
        ssfd.sin_family = AF_INET;            //  Set Internet address Family
        ssfd.sin_addr.s_addr = htonl( NULL ); //  Client address will be filled 
                                              //  in automatically
        ssfd.sin_port = htons( 1313 );        //  This sets the TCP port number 
		                              //to 1313
    }
    
    /*  note bind takes a pointer to a sockaddr 
        structures NOT sockaddr_in, you need to typecast */
    bindok = bind( s, ( struct sockaddr *)&ssfd, sizeof( ssfd ) ); //  call to bind 
    if( bindok < 0 ){
        printf("could not bind socket to file descriptor\n\r");
    }
    listen( s, 10);        //  listen for 10 clients Max
    c = accept( s, NULL, NULL );        //  call to accept
	

...

Sending Data

    to send data over a socket the program will need to make a call to send(); if the socket is non-blocking the send call should return immediately with the number of bytes that were successfully written to the sockets output queue.  The return from send does not indicate the number of bytes received on the other end of the connection nor does it indicate how large the tcp packet size is. But if you get a possetive return value on a send call it means the OS has taken responsibility for transmitting that data.  On a blocking socket send will return after all of the data has been sent or on an error.
the following code example shows how you would send to a connected socket.
    int i;

    /*  sockd is the connected socket file descriptor  */
    i = send( sockd, "Hello World!\n", 13, 0);
    if( i > 0 ){
        printf("sent %d bytes\n", i);
    } 	 

...

Receiving Data

    to receive data over a socket the program will need to make a call to recv(); if the socket is non-blocking the recv call should return immediately with the number of bytes that were successfully read from the sockets input queue.  The return from recv does not indicate the number of bytes sent by the remote host, nor does it indicate how large the tcp packet size was that was read.  On a blocking socket recv will return after all of the data specified has been received or on an error. It is also important to note that if recv() returns 0 ( zero ) that indicates the remote socket has closed the connection.
the following code example shows how you would use recv on a connected socket.
    int i;
    char buff[ 250 ];

    /*  clear out buff  */
    memset( buff, 0, sizeof( buff ) );

    /*  sockd is the connected socket file descriptor  */
    i = recv( sockd, buff, sizeof(buff), 0);
    if( i < 0 )
	{
	    printf("error recv'ing data %d\n", i);
	}
	if( i == 0 )
	{
	    printf("socket closed remotely\n");
	}
	if( i > 0 )
	{
        printf("received %d bytes\n", i);
        printf("data :\n%s", buff);
    }

...

Closing a socket

    There are only two ways to close a socket and both are fairly trivial
close( socket ); , and shutdown( socket, prio );
close( );, will close the socket imeediately, while shutdown, ill close the socket, after flushing certain buffers. you can specify what buffers shutdown should flush with an integer prio.
  The code example(s) below show how to use shutdown, and close, on a connected socket.
    /*  connected socket is int sockt  */

    /*  close socket imeediately */
    close( sockt );

    /*  close socket, and dont recieve any more */
    shutdown( sockt, 0);

    /*  close socket, and dont send any more */
    shutdown( sockt, 1);

    /*  close socket, and dont recieve, or send any more */
    shutdown( sockt, 2);

   

...

Usefull Functions / My API

    All of the functions below are included in the source files mfstd.h, and mfstd.c.

...

int init_tcp( int portno )

init_tcp( ), opens a tcp socket on the port specified by portno.
init_tcp will return a negative on an error, or the open socket handle on success.
if portno is equal to 0, init_tcp, will not bind the socket file descriptor to a port. the code for init_tcp( ), is below.
  /*  init_tcp( int portno )  */  
  int init_tcp( int portno )
  {
      int sd, slen, i;	/* socket file descriptor and length */
      struct sockaddr_in ssfd;

      /*  Open the socket  */
      if( ( sd = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 ){
          printf("Could not open socket %d\n\r", sd);
          return( sd );
      }
      if( portno != 0 ){
          if( sd > 0 ){
              ssfd.sin_family = AF_INET;
              ssfd.sin_addr.s_addr = htonl( NULL );
              ssfd.sin_port = htons( portno );
              slen = sizeof( ssfd );
          }
          /*  bind the socket to a local port  */
          if( ( i = bind( sd, ( struct sockaddr ) &ssfd, slen ) ) < 0 ){
              printf("could not bind socket to file descriptor %d\n\r", i);
              close( sd );
              return( i );
          }
      }
  return ( sd );
  }

...

int init_udp( int portno )

init_udp( ), opens a udp socket on the port specified by portno.
init_udp will return a negative on an error, or the open socket handle on success.
if portno is equal to 0, init_udp, will not bind the socket file descriptor to a port. the code for init_udp( ), is below.
  /*  init_udp( int portno )  */  
  int init_udp( int portno )
  {
      int sd, slen, i;	/* socket file descriptor and length */
      struct sockaddr_in ssfd;

      /*  Open the socket UDP  */
      if( ( sd = socket( AF_INET, SOCK_DGRAM, 0 ) ) < 0 ){
          printf("Could not open socket %d\n\r", sd);
          return( sd );
      }
      if( portno != 0 ){
          if( sd > 0 ){
              ssfd.sin_family = AF_INET;
              ssfd.sin_addr.s_addr = htonl( NULL );
              ssfd.sin_port = htons( portno );
              slen = sizeof( ssfd );
          }
          /*  bind the socket to a local port  */
          if( ( i = bind( sd, ( struct sockaddr ) &ssfd, slen ) ) < 0 ){
              printf("could not bind socket to file descriptor %d\n\r", i);
              close( sd );
              return( i );
          }
      }
  return ( sd );
  }

...

int tcp_connect( char *host, int portno )

tcp_connect will open a socket, and attempt to make a connection to the host and port specified. tcp_connect will return a negative value if it fails, or the connected socket file descriptor on success
the code for tcp_connect( ), is below.
  /*  int tcp_connect( char *host, int portno )  */  
  int tcp_connect( char *host, int portno )
  {
      int    sockfd;
      struct sockaddr_in     servaddr;     
      struct in_addr    *pptr;      /* in.h */
      struct hostent 	*hp;        /* netdb.h     */
	  int    conerr;                /*  connecton error variable  */

      /* look up using DNS or dotted quad */
      if ((hp = gethostbyname(host)) == NULL){
          printf( "gethostbyname failure - host not found\n\r" ); 
	      return( -1 );
      }
      /* make sure address is filled in structure */
      if ( ( pptr = ( struct in_addr * ) hp->h_addr ) == NULL ){
          printf("gethostbyname failure - no address\n\r");
          return( -1 );
      }
      /* set up socket */
      if ( ( sockfd = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 ){ 
          printf("socket failure\n\r");
          return( -1 );
      }
      /* set up server address */
      memset( &servaddr, 0, sizeof( servaddr ) );
      servaddr.sin_family = AF_INET;
      servaddr.sin_port = htons( portno );
      memcpy( &servaddr.sin_addr, pptr, sizeof( struct in_addr ) );

      /* connect to server */
      conerr = connect( sockfd, ( struct sockaddr *) &servaddr, sizeof( servaddr ));
      if ( conerr < 0 ) {  
          printf("\n\rconnect failure\n\r");
          close( sockfd );
          return( -1 );
      }
  return( sockfd );
  }

...

int tcp_connect_from( char *host, int portto, int portfrom )

tcp_connect_from will open a socket, and attempt to make a connection to the host and port specified, in addition tcp_connect_from uses tcp_init to allow users to specify a local port to initiate the connection from. tcp_connect_from will return a negative value if it fails, or the connected socket file descriptor on success
the code for tcp_connect_from( ), is below.
  /*  int tcp_connect_from( char *host, int portto, int portfrom )  */  
  int tcp_connect( char *host, int portno )
  {
      int    sockfd;
      struct sockaddr_in     servaddr;     
      struct in_addr    *pptr;      /* in.h */
      struct hostent 	*hp;        /* netdb.h     */
      int    conerr;                /*  connecton error variable  */

      /* look up using DNS or dotted quad */
      if ((hp = gethostbyname(host)) == NULL){
          printf( "gethostbyname failure - host not found\n\r" ); 
	      return( -1 );
      }
      /* make sure address is filled in structure */
      if ( ( pptr = ( struct in_addr * ) hp->h_addr ) == NULL ){
          printf("gethostbyname failure - no address\n\r");
          return( -1 );
      }
      /* set up socket */
      if ( ( sockfd = init_tcp( portfrom ) ) < 0 ){ 
          printf("socket failure\n\r");
          return( sockfd );
      }
      /* set up server address */
      memset( &servaddr, 0, sizeof( servaddr ) );
      servaddr.sin_family = AF_INET;
      servaddr.sin_port = htons( portto );
      memcpy( &servaddr.sin_addr, pptr, sizeof( struct in_addr ) );

      /* connect to server */
	  conerr = connect( sockfd, ( struct sockaddr *) &servaddr, sizeof( servaddr ));
      if ( conerr < 0 ) { 
          printf("\n\rconnect failure\n\r");
          close( sockfd );
          return( conerr );
      }
  return( sockfd );
  }

...

int sdprintf(int sock, const char *fmt, ...)

sdprintf, is just like fprintf, but instead of taking a file pointer, it takes a files descriptor, and uses send( ) to transmit the data, making it good for use with sockets.
the code for sdprintf( ), is below.
  /*  int sdprintf( int sock, const char *fmt, ... )  */  
  int sdprintf(int sock, const char *fmt, ... )
  {
      char buf[512];
      int len;
      va_list args;

      if ( sock < 0 )return -1;

      va_start( args, fmt );
      vsprintf( buf, fmt, args ); 
      va_end( args );

      return ( send( sock, buf, strlen( buf ), 0 ) );
  }
  

...

int udp_send_file(char *fname, char *ipaddr, int portto, int portfrom)

udp_send_file will attempt to open a file and send it across a UDP socket. it takes four parameters :
the first is a character pointer to a file name, the second is the IP address the file should be sent to, next is the port on the remote host that the file should be sent to, and finally, you can specify the port for the file to come from. If you specify port 0 for portfrom, a random port number will be picked. the code for udp_send_file( ), is below.
  /*  int udp_send_file( char *fname, char *ipaddr, int portto, int portfrom )  */  
  int udp_send_file(char *fname, char *ipaddr, int portto, int portfrom)
  {
      int    udpsock, i, n, fd, udplen;
      char   buff[250], chc;
      struct in_addr *udps;
      struct sockaddr_in udpsd;
      struct hostent   *hp;

      if( ( hp = gethostbyname( ipaddr ) ) == NULL ){
          printf("could not find host name\n\r");
          return -1;
      }
      if( ( udps = ( struct in_addr * ) hp-> h_addr ) == NULL ){
          printf("get hostname failure, no address\n\r");
          return -1;
      }
      if( ( fd = open( fname, O_RDONLY ) ) < 0 ){
          printf( "could not open file %s\n\r", fname );
          return ( fd );
      }
      if( (  udpsock = init_udp( portfrom ) ) < 0 ){
          printf( "could not pen UDP socket\n\r" );
          return ( udpsock );
      }
      memset( &udpsd, 0, sizeof( udpsd ) );
      udpsd.sin_family = AF_INET;
      udpsd.sin_port = htons( portto );
      memcpy( &udpsd.sin_addr, udps, sizeof(struct in_addr));
      udplen = sizeof( udpsd );
      while( read( fd, buff, sizeof( buff ) ) > 0 )
      {
          sendto( udpsock, buff, strlen( buff ), 0, ( struct sockaddr_in *)&udpsd, udplen );
          memset( buff, 0, sizeof( buff ) );
      }	   
      close( fd );
      close( udpsock );
  return 0;
  }
  

...

int tdp_send_file(char *fname, char *ipaddr, int portto, int portfrom)

tcp_send_file will attempt to open a file and send it across a TCP socket. it takes four parameters :
the first is a character pointer to a file name, the second is the IP address the file should be sent to, next is the port on the remote host that the file should be sent to, and finally, you can specify the port for the file to come from. If you specify port 0 for portfrom, a random port number will be picked. the code for tcp_send_file( ), is below.
  /*  int tcp_send_file( char *fname, char *ipaddr, int portto, int portfrom )  */  
  int tcp_send_file(char *fname, char *ipaddr, int portto, int portfrom)
  {
      int    tcpsock, i, n, fd, udplen;
      char   buff[250], chc;
      struct in_addr *udps;
      struct sockaddr_in udpsd;
      struct hostent   *hp;

      if( ( hp = gethostbyname( ipaddr ) ) == NULL ){
          printf("could not find host name\n\r");
          return -1;
      }
      if( ( udps = ( struct in_addr * ) hp-> h_addr ) == NULL ){
          printf("get hostname failure, no address\n\r");
          return -1;
      }
      if( ( fd = open( fname, O_RDONLY ) ) < 0 ){
          printf( "could not open file %s\n\r", fname );
          return ( fd );
      }
      if( (  tcpsock = init_tcp( portfrom ) ) < 0 ){
          printf( "could not open TCP socket\n\r" );
          close( fd );
          return ( tcpsock );
      }
      memset( &udpsd, 0, sizeof( udpsd ) );
      udpsd.sin_family = AF_INET;
      udpsd.sin_port = htons( portto );
      memcpy( &udpsd.sin_addr, udps, sizeof(struct in_addr));
      udplen = sizeof( udpsd );
      while( read( fd, buff, sizeof( buff ) ) > 0 )
      {
          sendto( tcpsock, buff, strlen( buff ), 0, ( struct sockaddr_in *)&udpsd, udplen );
          memset( buff, 0, sizeof( buff ) );
      }	   
      close( fd );
      close( tcpsock );
  return 0;
  }
  

.....

Referance

  
  • Beej's Guide to Network programming ( highly recommended )
  • Crash course in TCP / IP socket programming
  • Unix Programming links
  • Spencers Socket site
  • librenix programming TCP / IP resources
  • Socket programming in C... pont.net


  • http://www.spyder-fonix.com

  • .....

    Thank you to:

       Tracy Thomas for providing some good feedback on some lesser known ( or lesser thought of aspects of the recv() call)...

    and to
    Philippe De Neve for pointing out some differences between windows and Linux ( *NIX ) socket programming



    and Chris Booth, who wrote...
    "you saved my ass in my new job thanks..."

    no problem Chris, I wish I knew how I saved your ass, but whatever....
    http://www.spyder-fonix.com