Thread: TCP/IP Socket Programming Exercise

  1. #1
    Registered User
    Join Date
    Nov 2009
    Posts
    51

    TCP/IP Socket Programming Exercise

    I am following an exercise in a book which is suppose to create a simple TCP Echo Client which should just echo back to me what I type. It serves no real function other than a learning tool.

    So to run it for example it type the following format:

    ./TCP <SERVER IP> <ECHO WORD> [<ECHO PORT>]
    The book shows the following :

    ./TCP 169.1.1.1 "Test"
    When a port isn't specified it is automatically assigned port 7

    My problem is, however when I try this the program just shows a flashing block on the line below as if it's waiting / trying to connect.
    So, my next logical thought was to change the ip to the loopback address but this returns :

    connect() failed : Connection refused
    Has anyone any ideas? ANY HELP would be appreciated. I am running ubuntu (linux). The main code is as follows. However, it should be ok as it is a downloaded example so it's not like i've had to type it out and made a mistake :

    Code:
    #include <stdio.h>      /* for printf() and fprintf() */
    #include <sys/socket.h> /* for socket(), connect(), send(), and recv() */
    #include <arpa/inet.h>  /* for sockaddr_in and inet_addr() */
    #include <stdlib.h>     /* for atoi() and exit() */
    #include <string.h>     /* for memset() */
    #include <unistd.h>     /* for close() */
    
    #define RCVBUFSIZE 32   /* Size of receive buffer */
    
    void DieWithError(char *errorMessage);  /* Error handling function */
    
    int main(int argc, char *argv[])
    {
        int sock;                        /* Socket descriptor */
        struct sockaddr_in echoServAddr; /* Echo server address */
        unsigned short echoServPort;     /* Echo server port */
        char *servIP;                    /* Server IP address (dotted quad) */
        char *echoString;                /* String to send to echo server */
        char echoBuffer[RCVBUFSIZE];     /* Buffer for echo string */
        unsigned int echoStringLen;      /* Length of string to echo */
        int bytesRcvd, totalBytesRcvd;   /* Bytes read in single recv() 
                                            and total bytes read */
    
        if ((argc < 3) || (argc > 4))    /* Test for correct number of arguments */
        {
           fprintf(stderr, "Usage: %s <Server IP> <Echo Word> [<Echo Port>]\n",
                   argv[0]);
           exit(1);
        }
    
        servIP = argv[1];             /* First arg: server IP address (dotted quad) */
        echoString = argv[2];         /* Second arg: string to echo */
    
        if (argc == 4)
            echoServPort = atoi(argv[3]); /* Use given port, if any */
        else
            echoServPort = 7;  /* 7 is the well-known port for the echo service */
    
        /* Create a reliable, stream socket using TCP */
        if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
            DieWithError("socket() failed");
    
        /* Construct the server address structure */
        memset(&echoServAddr, 0, sizeof(echoServAddr));     /* Zero out structure */
        echoServAddr.sin_family      = AF_INET;             /* Internet address family */
        echoServAddr.sin_addr.s_addr = inet_addr(servIP);   /* Server IP address */
        echoServAddr.sin_port        = htons(echoServPort); /* Server port */
    
        /* Establish the connection to the echo server */
        if (connect(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0)
            DieWithError("connect() failed");
    
        echoStringLen = strlen(echoString);          /* Determine input length */
    
        /* Send the string to the server */
        if (send(sock, echoString, echoStringLen, 0) != echoStringLen)
            DieWithError("send() sent a different number of bytes than expected");
    
        /* Receive the same string back from the server */
        totalBytesRcvd = 0;
        printf("Received: ");                /* Setup to print the echoed string */
        while (totalBytesRcvd < echoStringLen)
        {
            /* Receive up to the buffer size (minus 1 to leave space for
               a null terminator) bytes from the sender */
            if ((bytesRcvd = recv(sock, echoBuffer, RCVBUFSIZE - 1, 0)) <= 0)
                DieWithError("recv() failed or connection closed prematurely");
            totalBytesRcvd += bytesRcvd;   /* Keep tally of total bytes */
            echoBuffer[bytesRcvd] = '\0';  /* Terminate the string! */
            printf("%s", echoBuffer);      /* Print the echo buffer */
        }
    
        printf("\n");    /* Print a final linefeed */
    
        close(sock);
        exit(0);
    }

  2. #2
    Registered User
    Join Date
    Oct 2006
    Location
    Canada
    Posts
    1,243
    Well the logical place to start is: what is the error? Use a "select" statement to find out what caused connect to fail, by checking "errno" against the various error constants (or use some function that does this for you). A list of some is here: connect - Linux Command - Unix Command.

    So do something like
    Code:
    if (connect(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0)
    {
       select (errno)
       {
         case EBADF: printf("EBADF\n");
         case // ...
        }
    Once you know what message is printing, then look to see what this message even means, then we get an idea of whats the general problem. Post which message is being printed once you find out.

  3. #3
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Port 7 is a standard port used for an echo service, but you will have to find a server that actually has one running -- your own computer almost certainly does not*.

    I think these are generally disabled now because they can be used in "smurf" or "fraggle" attacks, whereby someone sends an echo request using a spoofed ip to as many echo servers as they can. The servers then reply to the spoofed ip (which would be the victim of the attack); that ip is effectively flooded with incoming messages from all over the place.

    *ie, you cannot connect because there is no one to accept() the call.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  4. #4
    Registered User
    Join Date
    Nov 2009
    Posts
    51
    Thanks for reply,

    I only get a connection error if I put the loopback address in.If I enter the suggested command it justs waits with the cursor flashing.

    The code is a direct download so I assume it is correct. I just wondered if there was something more basic I had done wrong as I am new to C and new to networking.

    Thanks again

  5. #5
    Registered User
    Join Date
    Nov 2009
    Posts
    51
    Quote Originally Posted by MK27 View Post
    Port 7 is a standard port used for an echo service, but you will have to find a server that actually has one running -- your own computer almost certainly does not*.

    I think these are generally disabled now because they can be used in "smurf" or "fraggle" attacks, whereby someone sends an echo request using a spoofed ip to as many echo servers as they can. The servers then reply to the spoofed ip (which would be the victim of the attack); that ip is effectively flooded with incoming messages from all over the place.

    *ie, you cannot connect because there is no one to accept() the call.
    Thanks for reply.

    Hmm.... it's a recent print book. Is there a way to enable port 7 temporarily or is it not advised even short-term?

    Or is there a different port I could try that would be more likely to work?

    and do you have any idea what the suggested ip address 169.1.1.1 would be?

    Thanks again

  6. #6
    Registered User
    Join Date
    Oct 2006
    Location
    Canada
    Posts
    1,243
    Or is there a different port I could try that would be more likely to work?
    Yes, a few of them! You should be free to chose any of List of TCP and UDP port numbers - Wikipedia, the free encyclopedia

    and do you have any idea what the suggested ip address 169.1.1.1 would be?
    My first guess was that it is some local/private IP address. But apparently thats not the case (see 3. of RFC 1918 - Address Allocation for Private Internets). I think its some arbitrary public IP address that doesnt really mean anything.

  7. #7
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by Martin_T View Post
    Or is there a different port I could try that would be more likely to work?

    and do you have any idea what the suggested ip address 169.1.1.1 would be?

    Thanks again
    It is not that the port is "disabled", it is that there is there is nothing answering on that port. Ports are just abstractions so that a single address (eg, 169.1.1.1) can have a number of services running. So there might be an apache http web server running that answers to port 80, a separate ftp server on some other port, an IRC server on some other port, etc, all running on one computer with one network card with one address.

    But nothing in the network card or the operating system answers ports automatically. You have to provide some software.

    The code you have above is a simple client. What you need is a simple server as well -- this is the first thing people do learning networking, they write little clients and servers that work together. Gimme a few minutes and I'll post you something that should work like an echo server on a linux box...

    ps. I have no idea what 169.1.1.1 would be. In what sense is it "suggested"? I'm not even sure if that is a valid "A level" address, 169 could be a LAN address.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  8. #8
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Okay! I'm getting better at this

    Code:
    #include <stdio.h>      /* for printf() and fprintf() */
    #include <sys/socket.h> /* for socket(), connect(), send(), and recv() */
    #include <arpa/inet.h>  /* for sockaddr_in and inet_addr() */
    #include <stdlib.h>     /* for atoi() and exit() */
    #include <string.h>     /* for memset() */
    #include <unistd.h>     /* for close() */
    
    #define PORT 7
    
    int server_sock (int port) {
    	struct sockaddr_in Me;
    	int sock;
    	if ((sock=socket(PF_INET, SOCK_STREAM, 0))<3) perror("socket");
    	Me.sin_family=AF_INET;
    	Me.sin_port=htons(port);
    	Me.sin_addr.s_addr=INADDR_ANY;
    	memset(&(Me.sin_zero), '\0', 8);
    	if (bind(sock,(struct sockaddr*)&Me,sizeof(struct sockaddr))==-1) perror("bind");
    	if (listen(sock,2)!=0) perror("listen");
    	return sock;
    }
    
    int main() {
    	char buffer[256]; 
    	struct sockaddr_in info;
    	socklen_t size=sizeof(struct sockaddr_in);
    	int self = server_sock(PORT), 
    		other = accept(self,(struct sockaddr*)&info,&size);
    
    	recv(other,buffer,255,0);
    	send(other,buffer,strlen(buffer),0);
    	close(other);
    	close(self);
    
    	return 0;
    }
    Here's how this works, if you haven't played with client/server stuff yet:

    1. compile the above code as "server"
    2. compile your OP as "client"
    3. start the server "./server". You will notice it is just waiting in the foreground, meaning you can't use the terminal.
    4. So open another terminal and start the client "./client 127.0.0.1 helloWorld!"


    In the second terminal you will see:

    Received: helloWorld!

    and then both programs will end. I just tried this here (I had to add the "DieWithError" function to your code) and it works fine.

    Notice the server is automatically on the loopback interface, 127.0.0.1. I believe that most linux systems have this enabled by default -- if you have a problem, that is probably it, then we just have to figure out how to start that on your box
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  9. #9
    Registered User
    Join Date
    Nov 2009
    Posts
    51
    Quote Originally Posted by MK27 View Post
    It is not that the port is "disabled", it is that there is there is nothing answering on that port. Ports are just abstractions so that a single address (eg, 169.1.1.1) can have a number of services running. So there might be an apache http web server running that answers to port 80, a separate ftp server on some other port, an IRC server on some other port, etc, all running on one computer with one network card with one address.

    But nothing in the network card or the operating system answers ports automatically. You have to provide some software.

    The code you have above is a simple client. What you need is a simple server as well -- this is the first thing people do learning networking, they write little clients and servers that work together. Gimme a few minutes and I'll post you something that should work like an echo server on a linux box...

    ps. I have no idea what 169.1.1.1 would be. In what sense is it "suggested"? I'm not even sure if that is a valid "A level" address, 169 could be a LAN address.
    Thankyou for your reply. You have been extremely helpful. Now I read the paragraph again along with what you have just told me then I think it is just a badly set out example.

    The chapter is on the TCP client only and at the end gives an example where I compile this code and get a response. However, it looks like maybe the ip address should have an echo server running on it.

    Seems strange as the next chapter is on the tcp server at the end of which I run both client and server together.

    Sorry to be asking stupid questions, I just thought this code would take on both functions of sending a receiving.

  10. #10
    Registered User
    Join Date
    Nov 2009
    Posts
    51
    Quote Originally Posted by MK27 View Post
    Okay! I'm getting better at this

    Code:
    #include <stdio.h>      /* for printf() and fprintf() */
    #include <sys/socket.h> /* for socket(), connect(), send(), and recv() */
    #include <arpa/inet.h>  /* for sockaddr_in and inet_addr() */
    #include <stdlib.h>     /* for atoi() and exit() */
    #include <string.h>     /* for memset() */
    #include <unistd.h>     /* for close() */
    
    #define PORT 7
    
    int server_sock (int port) {
    	struct sockaddr_in Me;
    	int sock;
    	if ((sock=socket(PF_INET, SOCK_STREAM, 0))<3) perror("socket");
    	Me.sin_family=AF_INET;
    	Me.sin_port=htons(port);
    	Me.sin_addr.s_addr=INADDR_ANY;
    	memset(&(Me.sin_zero), '\0', 8);
    	if (bind(sock,(struct sockaddr*)&Me,sizeof(struct sockaddr))==-1) perror("bind");
    	if (listen(sock,2)!=0) perror("listen");
    	return sock;
    }
    
    int main() {
    	char buffer[256]; 
    	struct sockaddr_in info;
    	socklen_t size=sizeof(struct sockaddr_in);
    	int self = server_sock(PORT), 
    		other = accept(self,(struct sockaddr*)&info,&size);
    
    	recv(other,buffer,255,0);
    	send(other,buffer,strlen(buffer),0);
    	close(other);
    	close(self);
    
    	return 0;
    }
    Here's how this works, if you haven't played with client/server stuff yet:

    1. compile the above code as "server"
    2. compile your OP as "client"
    3. start the server "./server". You will notice it is just waiting in the foreground, meaning you can't use the terminal.
    4. So open another terminal and start the client "./client 127.0.0.1 helloWorld!"


    In the second terminal you will see:

    Received: helloWorld!

    and then both programs will end. I just tried this here (I had to add the "DieWithError" function to your code) and it works fine.

    Notice the server is automatically on the loopback interface, 127.0.0.1. I believe that most linux systems have this enabled by default -- if you have a problem, that is probably it, then we just have to figure out how to start that on your box

    Worked great thanks. Although it added a "K" to the end of the recieved data. And it wouldnt run a second time. It says "bind : Address already in use"

    But it worked fine to allow me to see the concept. Now all I've got to do is work through this book.

    Thankyou once again. I appreciate your time and your help.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Problem with socket descriptors
    By McKracken in forum C Programming
    Replies: 1
    Last Post: 07-22-2009, 08:51 AM
  2. Line of data input method
    By larry_2k4 in forum C Programming
    Replies: 2
    Last Post: 04-28-2009, 11:34 PM
  3. Request for comments
    By Prelude in forum A Brief History of Cprogramming.com
    Replies: 15
    Last Post: 01-02-2004, 10:33 AM
  4. TCP/IP and Socket programming
    By CompiledMonkey in forum C Programming
    Replies: 2
    Last Post: 02-21-2003, 03:47 PM
  5. TCP/IP Socket
    By Nor in forum Linux Programming
    Replies: 4
    Last Post: 04-22-2002, 11:21 AM