Thread: Need major c help

  1. #1
    Registered User lantzvillian's Avatar
    Join Date
    Sep 2010
    Posts
    44

    Angry Need major c help

    Hi all,

    I have a a big issue. I bridged from another university and C programming was not one of my requirements for bridging.... until now. I have a class that is going to use c heavily and I am getting pretty beat up and frustrated. No sob stories though since I had an inkling that c might be dependent so I started learning c in all of my spare moments.

    I know Java alright, particularly with Eclipse Products, and i know PHP fairly well also. I've spent probably close to about 20 hours smacking my head against the wall and would love to have a c god lend some advice/discussion.

    I'll upload what I have so far, and I DON'T WANT anyone to give me the answer.. in fact I would rather learn it with well advised discussion.. I would pay for tutoring as well if needs be.

    The fileclient.c was really where I was working, but it breaks horrendously on compile.. I was trying to figure out structures etc..

    Here is an excerpt on what I was trying to do:

    Objective: To implement a simple client-server using the TCP/IP protocol suite.
    Your Mission:

    · Design and implement a server application that will listen for connections from
    clients and once the connection has been established it will respond to file transfer
    commands from the client(s).
    · Design and implement a client application that will initiate a connection to a remote
    server, and will issue commands to the server to either send a file or to receive a file.
    · Supply the server information as command line arguments.
    · Implement two functions: GET and SEND in your application.
    · That is, a client can use the GET function to request a named file from a server.
    · Similarly it can use SEND to send a specified file to a remote server.

    Constraints:
    · The server will be designed to handle connections from multiple clients, i.e., a
    concurrent server.
    · The server will listen on port 7001 for connection requests. The client will connect to
    the control port on the server using a dynamic port (port X).
    · When a GET or SEND command is received by the server, the server will initiate a
    data connection from port 7000 to port X on the client machine.
    To Be

    Cheers - Hope to hear something soon.

  2. #2
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by lantzvillian View Post
    Hi all,
    I have a a big issue. I bridged from another university and C programming was not one of my requirements for bridging.... until now. I have a class that is going to use c heavily and I am getting pretty beat up and frustrated. No sob stories though since I had an inkling that c might be dependent so I started learning c in all of my spare moments.
    I'm guessing you'll get a lot of responses on this including the ones that say "Read the FAQ" and "read a book", both of which are very good advice.

    You do appear to have most of the socket concepts down fairly well. They will cause you problems of course, and fixing them will be a pretty interresting learning experience for you.

    However, you seem to be missing one of the primary concepts of C in that it's a "bottom up" language. Nothing is seen until it is defined... therefore your largest function --Main-- should be at the bottom of your page with functions ordered above it such that if you are calling FOO from BAR... FOO must be on the page above BAR. This will simplify your experience signficantly from what you were doing in your client program. It will also make debugging a lot simpler... as you are now laying things out in a much more logical fashion.

    Also; while it does work, it is generally a pretty bad idea to put executable code in a .h file. This too is organizational. You should write a separate C file then create a header with function prototypes to include in your other files. The logic behind this is that each page is a "scope" as are the insides of each function. By putting code in headers you defeat the scoping rules of the lanuguage. For your project you should have a "global.c" with your common code in it a "global.h" with prototypes only for your common code then in include the .h file into both programs. I know it's more complex but once you realize that you can create isolated functions and variable swithin a program, it makes a lot more sense.

    So right now it's a matter of form, more than substance...

  3. #3
    Registered User
    Join Date
    Jan 2010
    Location
    Ca, US
    Posts
    29
    In fileclient check your main arguments (and getCommandline).

    In your getCommandline() make use of the argc and check how many arguments were passed to your program, so you don't try and access parts of your argv that don't exist.

    Dylan

  4. #4
    Registered User lantzvillian's Avatar
    Join Date
    Sep 2010
    Posts
    44
    You were right not to mention rtfms and the like.. I have been reading them and two c books. The original C programming book and the definitive guide to networking as well.. Got more oreillys, but they are more advanced topics.

    Well thats encouraging.. I expected to hear that most of my code is junk.

    So in the case of moving main to the bottom, I heard that if you put the first line of every function at the top under lib declarations you would have the compiler forward process them? Other than that..


    argc and count them.. interesting, I hadn't thought of that, but the application only has 3 arguments.. if they aren't there it wouldn't work ? or it would be lacking variables and truck along?

  5. #5
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by lantzvillian View Post
    So in the case of moving main to the bottom, I heard that if you put the first line of every function at the top under lib declarations you would have the compiler forward process them? Other than that..
    Yes you can do that... but it significantly defeats the inherrent organizational structure of the language. Forward references should be used only when there's no other choice.

    It may not make a lot of sense right now but when you get into a big job and start getting "function not found" and similar errors you will appreciate why things are organized "bottom up".

  6. #6
    Registered User
    Join Date
    Sep 2010
    Location
    Halesowen, England
    Posts
    30
    Quote Originally Posted by CommonTater View Post
    Yes you can do that... but it significantly defeats the inherrent organizational structure of the language. Forward references should be used only when there's no other choice.
    I'm guessing we are talking about function prototypes here, which there is nothing wrong with. Every book I've ever read describes prototypes as necessary. It seems odd that you think they should only be used when necessary. I've never had any problem using them, and in fact it generally produces cleaner code in a big codebase (I usually work on code with 108 .c files and 66 .h files).

    You do have functions in your header file though, all functions should be in your .c files. Header files are for defines, structure definitions and function prototypes.

    It might be worth looking at some of the source code for freely downloadable FTP servers, or even MUDs as these handle client/server code and sending/receiving commands, and might be useful to your research. This code is also the basis for the huge MMORPG games (e.g. World of Warcraft), which (simplifying things a lot) relies on passing information between the server and client.

  7. #7
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by lantzvillian
    The fileclient.c was really where I was working, but it breaks horrendously on compile.. I was trying to figure out structures etc..
    Incidentally, zero length arrays are a compiler extension. You might want to check if that is the problem.

    Quote Originally Posted by CommonTater
    Also; while it does work, it is generally a pretty bad idea to put executable code in a .h file.
    I agree that it is a pretty bad idea, but actually, it does not always work to place function definitions (i.e., implementations) in a header file (which conventionally have a .h extension, but there is no such requirement in the language). If the header is included in more than one source file, then the same function would be defined more than once, typically resulting in a link/load error.

    Quote Originally Posted by CommonTater
    The logic behind this is that each page is a "scope" as are the insides of each function. By putting code in headers you defeat the scoping rules of the lanuguage.
    It is true that there is such a thing as file scope, but I do not think that "by putting code in headers you defeat the scoping rules of the lanuguage". The identifier is available at file scope even if you only declare it, but do not define it, in the header.

    Quote Originally Posted by CommonTater
    Yes you can do that... but it significantly defeats the inherrent organizational structure of the language. Forward references should be used only when there's no other choice.
    On the contrary, you are likely to be placing forward declarations in a corresponding header anyway. It can be easier to trace the flow of control by starting from the first function called and then going down to the functions that each caller calls.
    Last edited by laserlight; 09-26-2010 at 08:35 AM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  8. #8
    Registered User lantzvillian's Avatar
    Join Date
    Sep 2010
    Posts
    44
    OK.. I gave up on trying to look at other programs source.... scp.. wow too intense for me.

    So I have gotten a working client and server going where I can send a file from a client to a server with arguments (I tell the server what to name the file).

    Here is where I am stuck - and I am only focusing on the client uploading (send):

    Currently I tell the client what file to send through an argument (this is okay) and it sends the file to a server that knows what to file to write the data to (provided with an argument and thus not okay)

    What I want to be able to do is to send a controlpacket or signal to the server on command port 7001 and for it to get out of that packet the command (send of get) and the filename. At that point I am really starting to lose my sanity.

    So I have a struct:

    Code:
        
    struct cmd_s {
            char cmd[4];
            char filename[256];
        };
    and I could use this to be sent across the first connection. Now then on the server I could create an if statement where strcmp(buffer.cmd, "send") which would do:

    • create socket (port 7000 now) and get connect to the client somehow
    • tell the client sendtime
    • server writes data and closes socket



    I can't upload the make so I hope this will help out. It seems like most of your issues were about form not substance...

    Thanks guys I appreciate your help and looking forward to hear more.

  9. #9
    Registered User lantzvillian's Avatar
    Join Date
    Sep 2010
    Posts
    44
    Most likely I would put this into my if statement if arg[x] was send:

    Code:
      /* declare struct cmdtosend */
      struct cmd_s cmdtosend;
      int sentbytes = 0;
      memset(&cmdtosend,0,sizeof(cmdtosend));
      strcpy(cmdtosend.cmd,"send");
      strcpy(cmdtosend.filename,xfilename);
    
      sentbytes = sendto(fd, &cmdtosend, sizeof(cmdtosend), 0, (struct sockaddr *)&serv_cmdport,sizeof(serv_cmdport));
    
      if(sentbytes!= sizeof(cmdtosend)) {
        printf("Something went wrong");
        exit(-1);
      }

  10. #10
    Registered User
    Join Date
    Sep 2008
    Location
    Toronto, Canada
    Posts
    1,834
    Code:
    strcpy(cmdtosend.cmd,"send");
    Problem right there. You can not copy a 4 character string into a 4 byte array. You must allow for a trailing nul. char cmd[5] should do it.

  11. #11
    Registered User
    Join Date
    May 2009
    Posts
    4,183
    Quote Originally Posted by nonoob View Post
    Code:
    strcpy(cmdtosend.cmd,"send");
    Problem right there. You can not copy a 4 character string into a 4 byte array. You must allow for a trailing nul. char cmd[5] should do it.
    I agree with the above info.

    I would replace this with
    Code:
      struct cmd_s {
        char cmd[4];
        char filename[256];
      };
    with this
    Code:
    #define MAX_CMD_LENGTH 4
    #define MAX_FILENAME_LENGTH 255
    Code:
      struct cmd_s {
        char cmd[MAX_CMD_LENGTH+1];
        char filename[MAX_FILENAME_LENGTH+1];
      };
    Over the years it has help me to avoid some code errors.

    The above assumes you are using the both buffers to hold C style string.

    Tim S.

  12. #12
    Registered User lantzvillian's Avatar
    Join Date
    Sep 2010
    Posts
    44
    Hi guys.

    I noticed the char[5] vs the char[4] I didn't understand the reasoning, but if a trailing character to a string is the cause that makes sense to me.

    Wow it is amazing what one can accomplish in the time since I have started this thread. I have gotten a working application that performs the GET and the SEND functions. I am amazed!

    I only have two remaining issues however, I need to get the source address of the client so I can send a talkback packet to the client.

    Code:
    prep_sockaddr_in(&srcaddr2, "127.0.0.1", CLIENT_PORT);
    I know the CLIENT_PORT it is 12345, but I want to get the client address. I am using UDP sockets if that helps anyone.

    I tried the following to just print out the address, but it segfaults.

    Code:
     fprintf(stderr, "%s\n", inet_ntoa(srcaddr2.sin_addr));
    Ideas?

  13. #13
    Registered User lantzvillian's Avatar
    Join Date
    Sep 2010
    Posts
    44
    here is part of my int main() {
    Code:
        struct sockaddr_in srcaddr; // client address - ( not really needed for this example )
        struct sockaddr_in srcaddr2;
        int srcaddrSize; // client address size - ( not really needed for this example )
        FILE *output; // file to output to
        long outputSize = 0; // to store the expected # bytes to receive from client
        char buffer[BUFFER_SIZE]; // buffer to use for recving & writing
        int bread = 0; // temp-var for bytes read from socket
        int bwritten = 0; // temp-var for bytes written to file
        int fd, fd2; // socket descriptor
        
        printBanner();
    
    
        fd = get_bound_udp_socket(SERVER_ADDR, SERVER_PORT); //  Open socket for controls
        fd2 = get_bound_udp_socket(SERVER_ADDR, SERVER_DPORT);
        while (1) {
    
            struct cmd_s *cmdrecieved;
            char bufferd[BUFFER_SIZE];
    
            recvfrom(fd, bufferd, BUFFER_SIZE, 0, (struct sockaddr *) & srcaddr, (socklen_t*) & srcaddrSize);
    
            cmdrecieved = (struct cmd_s *) bufferd;
            printf("Server recieved cmd: %s \n", cmdrecieved->cmd); // This works
    
            //This is what I would like it to do
            if (strncmp(cmdrecieved->cmd, "send", 3) == 0) {
                printf("Function recieved: %s \n", cmdrecieved->cmd);
    
                //  Open up a socket on 7000 the dataport
                //fd2 = get_bound_udp_socket(SERVER_ADDR, SERVER_DPORT);  // Socket for controls
    
    
                //  Prepare command packet to be sent to the client.
                //  TODO: need Client Address
                //  we have port 12345, verified with Wireshark
                //  Lets assume 127.0.0.1 for now
    	   // fprintf(stderr, "%s\n", inet_ntoa(srcaddr2.sin_addr));
                prep_sockaddr_in(&srcaddr2, "127.0.0.1", CLIENT_PORT);
    This might be enough to lend a hand for some suggestions.

Popular pages Recent additions subscribe to a feed