• C

Unix Socket Programming - Get Host information and send file contents to the server client.

Hi All,

I'm very new to programming and especially socket programming, I'm trying to write a client which does the following over TCP:

- Gets the fqdn of the server
- Gets any other names that the server may be known by
- Gets the IP address of the server
- Reads the contents of a file in the current directory and sends the contents to the server client. The file will contain about 36characters max.
- Waits to get an ACK from the on successfull receipt of the full message and displays that the message has been received by the server.

The server piece is deployed on the same machine and is listening on port 54203.

I have no idea where to begin and what to do here, can somebody please help.  

Thanks!!

This is what I have been able to piece together so far, what include files should I include??

return_value = gethostname(name_buffer,sizeof(name_buffer));
 
  if (return_value == 0) {           //got address
   
    s_hostent = gethostbyname(name_buffer);

     if (s_hostent != NULL) {    //got name of server
        for ( i = 0; s_hostent->h_addr_list[i] != 0; i++) {
        in_server_address.s_addr = *s_hostent->h_addr_list[i];
        printf("Server is running on %s...\n",inet_ntoa(in_server_address));
      }
     
    }

}



int name=strlen(filename);
send(name,4)
send(nameof(filename));
while(eof)
{
readfromfile
sendto socket;
}
close;

r5ur5Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

GloomyFriarCommented:
windows? unix? ...?
0
Kent OlsenData Warehouse Architect / DBACommented:

Hi r5ur5,

Here are the 5 steps that you described.  Let me address each of them:

- Gets the fqdn of the server

From where?  The address will need to come from a configuration file, variable, or typed by a user.

- Gets any other names that the server may be known by

If you've got access to linux source, look over the code for dig() and nslookup().  You will have to query a DNS for the other names and both of these routines display all of the names known to the DNS.

- Gets the IP address of the server

The same code that gets all of the registered names from the DNS will also get the IP address.

- Reads the contents of a file in the current directory and sends the contents to the server client. The file will contain about 36characters max.

"to the server client"?  I assume that you mean "to the server socket".  Very easy.  The server is in a listen() state on the socket and when something arrives it does a read on the socket.  The client program attempts to open a socket connection on the port, and once complete writes the message to the socket.

- Waits to get an ACK from the on successfull receipt of the full message and displays that the message has been received by the server.

If you're using TCP, you can safely assume that the message arrived at the server.  If you really do want to receive a return message, the server needs to send a message back to the client.


Kent
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
r5ur5Author Commented:
The client is what I will need to write up and the server piece is already written and deployed on the same machine. The environment is UNIX. The client code needs to determine what the ip address of the host is (on which the client  & the server code both are deployed), what the fully qualified domain name of the host is and also if there are any aliases. I don't know if my implementation of the gethostname is correct or not.

Hope this helps.

Thanks.
0
What were the top attacks of Q1 2018?

The Threat Lab team analyzes data from WatchGuard’s Firebox Feed, internal and partner threat intelligence, and a research honeynet, to provide insightful analysis about the top threats on the Internet. Check out our Q1 2018 report for smart, practical security advice today!

Kent OlsenData Warehouse Architect / DBACommented:


Let's start from the middle and work out.  :)

Since the client and the server are running on the same machine, you can start by testing the connect/send/receive logic.

Connect to the socket on IP address 127.0.0.1 (localhost).  The system will connect your client to the server running on the same machine that is listening to the specified port.  You can then send and receive data and make sure that your "protocols" are correct.

Then we can work backwards, and build in the communications necessary to move the client to another machine.

Kent
0
sunnycoderCommented:
I think Kents questions are important before you can get appropriate help...
>From where?  The address will need to come from a configuration file, variable, or typed by a user.
to add, you may need to query a DNS ....

so address his questions one by one just like he addressed your issues in his post
0
r5ur5Author Commented:
Kent,

I'm not sure how the address and alias information will be taken, that is why I was thinking of using gethostbyname() function and gethostaddr(). The server code and the client code are both to reside on the same physical box, but the requirement here is still to get the actual IP address of that machine and any aliases associated with it. I can try to use the functions above and see if there is any reverse lookup function also.

As for sending the conetnets of the file, I assume I would first need to initiate the socket (in client code) to connect to the server side socket and then do read, write functions. The only problem is I have no idean on how to write syntax I will still try. Your help is greatly appreciated.

Thanks a ton.  :-)

0
Kent OlsenData Warehouse Architect / DBACommented:

You gethostname() and gethostbyname() calls look good so you should have a valid host_ent pointer.

However, your setting of in_server_addr.s_addr is suspect.  It appears that you are trying to move the IP address one octet (byte) at a time, but the result seems to be that each octet is copied into the same cell.  You need to index the receiving field as well.


Kent
0
sunnycoderCommented:
>I'm very new to programming and especially socket programming
http://www.ecst.csuchico.edu/~beej/guide/net/html/
read this tutorial ... It is simple and easy to follow ... you will feel lot more confident after reading this.
here is a section from that tutorial which guides you how to use gethostbyname and related functions

4.10. gethostname()--Who am I?
Even easier than getpeername() is the function gethostname(). It returns the name of the computer that your program is running on. The name can then be used by gethostbyname(), below, to determine the IP address of your local machine.

What could be more fun? I could think of a few things, but they don't pertain to socket programming. Anyway, here's the breakdown:

    #include <unistd.h>

    int gethostname(char *hostname, size_t size);

 

The arguments are simple: hostname is a pointer to an array of chars that will contain the hostname upon the function's return, and size is the length in bytes of the hostname array.

The function returns 0 on successful completion, and -1 on error, setting errno as usual.

4.11. DNS--You say "whitehouse.gov", I say "198.137.240.92"
In case you don't know what DNS is, it stands for "Domain Name Service". In a nutshell, you tell it what the human-readable address is for a site, and it'll give you the IP address (so you can use it with bind(), connect(), sendto(), or whatever you need it for.) This way, when someone enters:

    $ telnet whitehouse.gov

 

telnet can find out that it needs to connect() to "198.137.240.92".

But how does it work? You'll be using the function gethostbyname():

    #include <netdb.h>
   
    struct hostent *gethostbyname(const char *name);

 

As you see, it returns a pointer to a struct hostent, the layout of which is as follows:

    struct hostent {
        char    *h_name;
        char    **h_aliases;
        int     h_addrtype;
        int     h_length;
        char    **h_addr_list;
    };
    #define h_addr h_addr_list[0]

 

And here are the descriptions of the fields in the struct hostent:


h_name -- Official name of the host.

h_aliases -- A NULL-terminated array of alternate names for the host.

h_addrtype -- The type of address being returned; usually AF_INET.

h_length -- The length of the address in bytes.

h_addr_list -- A zero-terminated array of network addresses for the host. Host addresses are in Network Byte Order.

h_addr -- The first address in h_addr_list.

gethostbyname() returns a pointer to the filled struct hostent, or NULL on error. (But errno is not set--h_errno is set instead. See herror(), below.)

But how is it used? Sometimes (as we find from reading computer manuals), just spewing the information at the reader is not enough. This function is certainly easier to use than it looks.

Here's an example program:

    /*
    ** getip.c -- a hostname lookup demo
    */

    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <netdb.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>

    int main(int argc, char *argv[])
    {
        struct hostent *h;

        if (argc != 2) {  // error check the command line
            fprintf(stderr,"usage: getip address\n");
            exit(1);
        }

        if ((h=gethostbyname(argv[1])) == NULL) {  // get the host info
            herror("gethostbyname");
            exit(1);
        }

        printf("Host name  : %s\n", h->h_name);
        printf("IP Address : %s\n", inet_ntoa(*((struct in_addr *)h->h_addr)));
       
       return 0;
    }

 

With gethostbyname(), you can't use perror() to print error message (since errno is not used). Instead, call herror().

It's pretty straightforward. You simply pass the string that contains the machine name ("whitehouse.gov") to gethostbyname(), and then grab the information out of the returned struct hostent.

The only possible weirdness might be in the printing of the IP address, above. h->h_addr is a char*, but inet_ntoa() wants a struct in_addr passed to it. So I cast h->h_addr to a struct in_addr*, then dereference it to get at the data.


I would strongly advise reading the guide thorougly... As a matter of fact, it covers almost everything you will need to code your application (except file opening and reading ;o))

Cheers!
Sunny:o)
0
r5ur5Author Commented:
Sunny,

Thanks so much for directing me to the site, this is what I have been able to put together. I still need to know how to get a list of all the aliases for a host, and also need to figure out how to wait for an ack from the server and display that on screen. Can you please help me with that? PLease please please.

******CODE*************

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define SERVER_PORT 54203
#define BUF_SIZE 512
//#define h_addr h_addr_list[0]



int main(int argc, char *argv[])
    {
        int sd, rc, i;
        struct sockaddr_in localAddr, servAddr;
        struct hostent *h;
        FILE *f;
        char s[64];
        char send_to_buf[BUF_SIZE];
        char file_name[64];

        if (argc != 2) {  // error check the command line
            fprintf(stderr,"usage: ./client [hostname]\n");
            exit(1);
        }

        if ((h=gethostbyname(argv[1])) == NULL) {  // get the host info
            herror("gethostbyname");
            exit(1);
        }

        printf("Host name  : %s\n", h->h_name);
        printf("IP Address : %s\n", inet_ntoa(*((struct in_addr *)h->h_addr)));
        printf("Alias Name : %s\n", h->h_aliases);   *****THIS GIVE A BLANK LINE RIGHT NOW**
        //return 0;

        servAddr.sin_family = h->h_addrtype;
        memcpy((char *) &servAddr.sin_addr.s_addr, h->h_addr_list[0], h->h_length);
        servAddr.sin_port = htons(SERVER_PORT);

        /* create socket */
        sd = socket(AF_INET, SOCK_STREAM, 0);
        if(sd<0) {
        perror("cannot open socket ");
exit(1);
        }

        /* bind any port number */
        localAddr.sin_family = AF_INET;
        localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
        localAddr.sin_port = htons(0);

        rc = bind(sd, (struct sockaddr *) &localAddr, sizeof(localAddr));
        printf("%s: bind port TCP %u\n",argv[0],SERVER_PORT);
        if(rc<0) {
        printf("%s: cannot bind port TCP %u\n",argv[0],SERVER_PORT);
        perror("error ");
        exit(1);
        }

        /* connect to server */
        rc = connect(sd, (struct sockaddr *) &servAddr, sizeof(servAddr));
        if(rc<0) {
        perror("cannot connect ");
        exit(1);
        }

        for(i=2;i<argc;i++) {

        rc = send(sd, argv[i], strlen(argv[i]) + 1, 0);

        if(rc<0) {
        perror("cannot send data ");
        close(sd);
        exit(1);

    }

    printf("%s: data%u sent (%s)\n",argv[0],i-1,argv[i]); ***DON't know what this means****


  }
        //f=fopen("input.txt","r");   ****I would like to use this function, where the name of the file
        //if (!f)                              ****is static but don't know how to pass that to the buffer.
        //      return 1;
        //while (fgets(s,64,f) !=NULL)
        //fgets(send_to_buf, BUF_SIZE, f);
        //printf("\ndata: %s\n", send_to_buf);

        //fclose(f);
        printf("\nPlease enter the name of the file to transmit: ");
        fgets(file_name, 64, stdin);
      file_name[strlen(file_name)-1] = '\0';

        if((f = fopen(file_name, "rt")) == NULL)
        {
                herror("fopen");
                return -1;
        }
        fgets(send_to_buf, BUF_SIZE, f);
        printf("\ndata: %d\n", send_to_buf);
        fclose(f);

return 0;
  *****HOW DO I WAIT FOR AN ACK FROM THE SERVER THAT DATA IS RECEIVED??*********
}

**********END CODE************


Thanks a ton!!

r5ur5
0
sunnycoderCommented:
> still need to know how to get a list of all the aliases for a host, and
look at the following section very carefully and you would know
But how does it work? You'll be using the function gethostbyname():

   #include <netdb.h>
   
   struct hostent *gethostbyname(const char *name);

 

As you see, it returns a pointer to a struct hostent, the layout of which is as follows:

   struct hostent {
       char    *h_name;
       char    **h_aliases;
       int     h_addrtype;
       int     h_length;
       char    **h_addr_list;
   };
   #define h_addr h_addr_list[0]

 

And here are the descriptions of the fields in the struct hostent:


h_name -- Official name of the host.

*** h_aliases -- A NULL-terminated array of alternate names for the host. ****

h_addrtype -- The type of address being returned; usually AF_INET.

h_length -- The length of the address in bytes.

h_addr_list -- A zero-terminated array of network addresses for the host. Host addresses are in Network Byte Order.

h_addr -- The first address in h_addr_list.


>also need to figure out how to wait for an ack from the server and display that on screen.
If you are using connected sockets/TCP sockets/SOCK_STREAM (which as I see you are), then you do not need a separate ACk .. the ACK is received and processed by the underlying protocol before it shows you success.
0
r5ur5Author Commented:
Sunny,

Thanks for the description, I guess I had overlooked this while reading the guide it makes sense now. My only doubt at this point is the code about opening the file and sending the data in the file to the server. How can I make the commented code work?

 //f=fopen("input.txt","r");   ****I would like to use this function, where the name of the file
        //if (!f)                              ****is static but don't know how to pass that to the buffer.
        //      return 1;
        //while (fgets(s,64,f) !=NULL)
        //fgets(send_to_buf, BUF_SIZE, f);
        //printf("\ndata: %s\n", send_to_buf);

        //fclose(f);

This does not ask the user to input a file but instead picks the file directly from the working path, how would I make sure that the file is being read and the data is being sent.  With the following code :

printf("\nPlease enter the name of the file to transmit: ");
        fgets(file_name, 64, stdin);
     file_name[strlen(file_name)-1] = '\0';

        if((f = fopen(file_name, "rt")) == NULL)
        {
                herror("fopen");
                return -1;
        }
        fgets(send_to_buf, BUF_SIZE, f);
        printf("\ndata: %d\n", send_to_buf);
        fclose(f);

return 0;

I am able to get some indication that data was sent, I get back something like  -4245921 (this is not the exact number but) this is what I get back. Is there any way to put a check somewhere to see whether the data is actually being sent or not?

Thanks,
r5ur5



0
sunnycoderCommented:
      f=fopen("input.txt","r");

       if ( f == NULL )        
             return 1;

       while (fgets(s,64,f) !=NULL)      
             printf("\ndata: %s\n", s);

       fclose(f);

to send, add a send() in the while loop ...

> Is there any way to put a check somewhere to see whether the data is actually being sent or not?
check return value of send() .. also check the contents received at the server side
0
r5ur5Author Commented:
I added the following:

f=fopen("input.txt","r");

       if ( f == NULL )        
             return 1;

       while (fgets(s,64,f) !=NULL)
             rc = send(sd, argv[i], strlen(argv[i]) + 1, 0)
             printf("\ndata: %s\n", s);

       fclose(f);

The program complies but I get a message when running, "Segmentation Fault".  No idea what this means...


0
sunnycoderCommented:
segmentation fault means that you are trying to access memory which does not belong to your process
 
while (fgets(s,64,f) !=NULL)  .... what is the declaration for s .. does it have 64 bytes ?
{
             rc = send(sd, argv[i], strlen(argv[i]) + 1, 0);     .... you read from file in buffer s but you are sending argv[i] ????
             printf("\ndata: %s\n", s);
}
0
r5ur5Author Commented:
s is defined as:

char s[64];

what should I be sending instead of argv?

changed the send to following:

f=fopen("input.txt","rt");
        if (f == NULL)
                return 1;
        while (fgets(s,64,f) !=NULL)
        {
              rc = send(sd, s, strlen(s) + 1, 0);
              printf("\ndata: %s\n", send_to_buf);
        }
        fclose(f);

Program complies and runs but I see the value of Data: being output to screen as blank, does this mean that data has been sent.
Unfortunately I don't have access to the server code to verify the receipt of data. I am really really greatful for your help!

Thank you so much!


0
sunnycoderCommented:
f=fopen("input.txt","rt");
       if (f == NULL)
               return 1;
       while (fgets(s,64,f) !=NULL)
       {
             rc = send(sd, s, strlen(s) +1 , 0);
             printf("\ndata: %s\n", s);
       }
       fclose(f);

are you sure your file will never have a line containing more than 64 chars ? If it has, this code will crash...

Also there is no error checking built into the program ... it is a good practice ....

right now,  what happens if fopen() fails .... you proceed with fgets() on an unopened file and program will crash ... such events are avoided by adding error checks and allowing application handle errors or at very minimum exit gracefully instead of crashing
0
Kent OlsenData Warehouse Architect / DBACommented:

Split 'em.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.