Like Tree8Likes

FTP server trouble

This is a discussion on FTP server trouble within the Networking/Device Communication forums, part of the General Programming Boards category; I've been sitting at my laptop for a few hours in my local coffee shop trying to get this right. ...

  1. #1
    Registered User Annonymous's Avatar
    Join Date
    Apr 2011
    Location
    Jackson, New Jersey, United States
    Posts
    302

    FTP server trouble

    I've been sitting at my laptop for a few hours in my local coffee shop trying to get this right. I am kinda spaced out from sitting at this comp and cant think logically at the moment. SO i am going to take a break and post what i have and would appreciate if someone could help point me in the right direction. Thanks

    SIDE NOTE: Within the for loop for the data is where the problem lies.

    Code:
    #include <stdio.h> 
    #include <string.h> 
    #include <stdlib.h> 
    #include <unistd.h> 
    #include <sys/socket.h> 
    #include <sys/types.h> 
    #include <netdb.h> 
    #include <netinet/in.h> 
    #include <arpa/inet.h>
    #include <errno.h>
    
    int main(int argc, char *argv[]) { 
    int sockfd, portno, readfd, writefd, yes = 1; 
    char buffer[1026];  
    struct hostent *server; 
    struct sockaddr_in serv_addr, cli_addr;
    
    
    	if(argc < 3) fprintf(stderr, "Ussage: %s IP Address port #", argv[0]);
    
    sockfd = socket(AF_INET, SOCK_STREAM, 0); 
    	if(sockfd < 0)  
    	{
    	fprintf(stderr, "%s.", strerror(errno));
    	exit(1);
    	}
    
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
    
    bzero((char *) &serv_addr, sizeof(serv_addr)); 
    server = gethostbyname(argv[1]); 
    	if(server == NULL) 
    	{
    	fprintf(stderr, "No such host.");
    	printf("%s", strerror(errno)); 
    	exit(1);
    	}
    portno = atoi(argv[2]); 
    serv_addr.sin_family = AF_INET; 
    memcpy(&serv_addr.sin_addr.s_addr, server->h_addr, server->h_length); 
    serv_addr.sin_port = htons(portno);
    
    	if(connect(sockfd, (const struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
    	  { 
    	  fprintf(stderr, "%s. CONNECT()\n", strerror(errno));
    	  exit(1);
    	  } 
    		else 
    		{ 
    		  fprintf(stdout, "Made a connection to %s\n", inet_ntoa(serv_addr.sin_addr)); 
    		}
    
    for( ; ; ) { 
    //Compilation errors.
    //---> ubuntu@ubuntu:~/Documents$ gcc -Wall client.c -o client
    //     client.c: In function ‘main’:
    //     client.c:62: warning: passing argument 1 of ‘fgets’ discards qualifiers from pointer target type
    //     /usr/include/stdio.h:624: note: expected ‘char * __restrict__’ but argument is of type ‘const char *’
    //     client.c:62: warning: ‘file’ may be used uninitialized in this function
    
    int i = sizeof(buffer)-1; if(i > 0) bzero(buffer, sizeof(buffer)); 
    ssize_t bytes;
    int file_t;
    const char *file;
    
    	//Goal here is to take in path of file with fgets. Use open to turn 
    	//file path into FD. Read the FD into my buffer.
      	fprintf(stdout, "Path of file to be transfer: \n");
    	fgets(file, strlen(file)-1, stdin); 
    
    	file_t = open(file, O_RDONLY);
    	if(file_t < 0)
    	{
    	printf("%s. FOPEN()\n", strerror(errno));
    	exit(0);
    	}
    
    	bytes = read(file_t, buffer, sizeof(buffer));
    	
    	if(bytes == 0)
    	{
    	printf("NULL buffer. READ(0)\n");
    	exit(0);
    	}
    
    	if(bytes < 0)
    	{
    	printf("%s. READ(-1)\n", strerror(errno));
    	exit(0);
    	}
    	
    writefd = write(sockfd, buffer, strlen(buffer)-1);
    	if(writefd < 0)
    	{ 
    	fprintf(stderr, "%s. WRITE(c)\n", strerror(errno));
    	exit(1);
    	}
    
    	if(writefd == 0)
    	{
    	printf("Nothing was written.\n");
    	exit(1);
    	}
    	
    	if(writefd)
    	{
    	  printf("Waiting for %s\n", inet_ntoa(serv_addr.sin_addr));
    	}
    
    
    i = sizeof(buffer); if(i > 0) bzero(buffer, sizeof(buffer)-1); 
    readfd = read(sockfd, buffer, sizeof(buffer));  
    
    	if(readfd < 0)	
    	{ 
    	fprintf(stderr, "Error reading message from %s\n", inet_ntoa(cli_addr.sin_addr)); 
    	printf("%s. READ(c)\n", strerror(errno));
    	exit(1);
    	} 
    	
    	//Test to see if the buffer is blank. Uncomment to test.
    	if(readfd == 0)
    	{
    	printf("Null buffer. READ()\n");
    	exit(1);
    	}
    		
    		else 
    		{
    		  fprintf(stdout, "%s", buffer);
    		}
    
    }
    
    close(sockfd);
    
    return 0;
    }
    BTW, this is just a basis to start me off. I will eventually clean and fix it up! Thanks
    Last edited by Annonymous; 12-27-2011 at 04:14 PM.

  2. #2
    Registered User Annonymous's Avatar
    Join Date
    Apr 2011
    Location
    Jackson, New Jersey, United States
    Posts
    302
    Fixed it. I needed to omit the const qualifier, but now the program crashes. Back to the drawing board.

  3. #3
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,444
    client.c:62: warning: ‘file’ may be used uninitialized in this function
    That warning is a big hint to a problem:
    Code:
    const char *file;
     
        //Goal here is to take in path of file with fgets. Use open to turn
        //file path into FD. Read the FD into my buffer.
        fprintf(stdout, "Path of file to be transfer: \n");
        fgets(file, strlen(file)-1, stdin);
    file is an uninitialized pointer. You try to fill it up with a call to fgets, but it doesn't point to memory you can fill, so that's a potential problem. Also, you call strlen on it in the fgets call, which is another problem. You can't take the length of a string that doesn't exist. Try:
    Code:
    char file[MAX_FILE_LEN];
    ...
    fgets(file, sizeof(file), stdin);
    Just #define MAX_FILE_LEN as an appropriate value.

    EDIT: Note, I didn't look at any of the rest of your code, just those 3 lines or so. Also, make sure you trim the trailing '\n' that fgets leaves.
    Last edited by anduril462; 12-27-2011 at 06:00 PM.
    Salem and rags_to_riches like this.

  4. #4
    and the hat of wrongness Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    32,451
    Repeating the same mistakes over and over -> server/client trouble yet again lol

    With the addition you're now mixing up strlen() and sizeof()
    rags_to_riches likes this.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.
    I support http://www.ukip.org/ as the first necessary step to a free Europe.

  5. #5
    Registered User Annonymous's Avatar
    Join Date
    Apr 2011
    Location
    Jackson, New Jersey, United States
    Posts
    302
    lol i dont see the same problem now as i had before. The problem i am having now is that once i get the pathname from the user and i open a file with it, i cant figure out how to put that data into a buffer. I have tried sprintf but i cannot use a struct FILE * as an argument.

    That problem had to do with chatting which is pretty straight forward! This is the transfer of a file. Def a different issue. Yes i am having trouble as to which operator to use, sizeof versus strlen. I do know that strlen should be used with the write function instead of sizeof. Besides that i cannot differentiate between the two uses.

    I dont appreciate you making me look ...incompetent. Not the word i was looking for but it will suffice. You have done this more than once and will probably continue to do if if the problem persists. I don't appreciate it! if you have the time to look at my post and respond like you did, you also have time to post a helpful reply instead of reply like a jerk!
    Last edited by Annonymous; 12-28-2011 at 09:17 AM.

  6. #6
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,444
    Quote Originally Posted by Annonymous View Post
    lol i dont see the same problem now as i had before. The problem i am having now is that once i get the pathname from the user and i open a file with it, i cant figure out how to put that data into a buffer. I have tried sprintf but i cannot use a struct FILE * as an argument.
    If you're still having trouble filling a buffer from a file, then drop the whole networking business and just work on your basics like data types, memory allocation and file handling. Some tutorials to get you started are here: Intro C Tutorial - C Made Easy - Learn C - Cprogramming.com.

    That problem had to do with chatting which is pretty straight forward! This is the transfer of a file. Def a different issue. Yes i am having trouble as to which operator to use, sizeof versus strlen. I do know that strlen should be used with the write function instead of sizeof. Besides that i cannot differentiate between the two uses.
    I think Salem was referring to a more general problem of not understanding the basics of types, sizes, memory allocation, strings, etc. As for what you "do know", you're not entirely right. You always want to give the write function the number of bytes you intend on sending. For strings, that would be strlen. You should use sizeof when the actual data type is the thing you want to send (e.g. an int, struct, etc). This never applies to pointers or char buffers that hold strings, which may not occupy the whole buffer, hence using strlen. As for a note on why you shouldn't use sizeof with pointers in this case, read this: Question 7.28.
    rags_to_riches likes this.

  7. #7
    Registered User Annonymous's Avatar
    Join Date
    Apr 2011
    Location
    Jackson, New Jersey, United States
    Posts
    302
    Id like to thank everyone who helped...oh wait, noone did lol I actually got it. I solved the issues after spending a decent amount of time on my laptop. Thanks for nothing friends.

  8. #8
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by Salem View Post
    Repeating the same mistakes over and over -> server/client trouble yet again lol

    With the addition you're now mixing up strlen() and sizeof()
    Definition of "Functional Insanity": Repeating the same failed patterns over and over again while expecting a different result.

  9. #9
    Registered User Annonymous's Avatar
    Join Date
    Apr 2011
    Location
    Jackson, New Jersey, United States
    Posts
    302
    Thanks commontater. Anywho, I have spent a few weeks on it and have learned quite a bit. This is just the base and i am going to greatly modify it. Mainly, integrating the concepts and suggestions MK27 and Salem have supplied in another post. Here is the source code for my unfinished project. If its cool with everyone; May you tell me what i could do better? What have i done wrong or change. Thanks

    Code:
    #include <stdio.h> 
    #include <string.h> 
    #include <stdlib.h> 
    #include <unistd.h> 
    #include <sys/socket.h> 
    #include <sys/types.h> 
    #include <netdb.h> 
    #include <netinet/in.h> 
    #include <arpa/inet.h>
    #include <errno.h>
    
    int main(int argc, char *argv[]) { 
    int sockfd, portno, readfd, writefd, yes = 1; 
    char buffer[1026];
    memset(buffer, 0, sizeof(buffer)); 
    struct hostent *server; 
    struct sockaddr_in serv_addr, cli_addr;
    
    	if(argc < 4) 
    	{
    	fprintf(stderr, "Ussage: %s + IP Address + port No. + file path.\n", argv[0]);
    	exit(0);
    	}
    
    sockfd = socket(AF_INET, SOCK_STREAM, 0); 
    	if(sockfd < 0)  
    	{
    	fprintf(stderr, "%s.", strerror(errno));
    	exit(1);
    	}
    
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
    
    bzero((char *) &serv_addr, sizeof(serv_addr)); 
    server = gethostbyname(argv[1]); 
    	if(server == NULL) 
    	{
    	fprintf(stderr, "No such host.\n");
    	printf("%s\n", strerror(errno)); 
    	exit(1);
    	}
    portno = atoi(argv[2]); //Grabbing the port number from the command line
    serv_addr.sin_family = AF_INET; 
    memcpy(&serv_addr.sin_addr.s_addr, server->h_addr, server->h_length); 
    serv_addr.sin_port = htons(portno);
    
    	if(connect(sockfd, (const struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
    	  { 
    	  fprintf(stderr, "%s. CONNECT()\n", strerror(errno));
    	  exit(1);
    	  } 
    		else 
    		{ 
    		printf("Made a connection to %s\n", inet_ntoa(serv_addr.sin_addr)); 
    		}
    
    for( ; ; ) 
    {
    int size, count = 0;
    
    FILE *fd;
    fd = fopen(argv[3], "r");
    
    fseek(fd, 0, SEEK_END);
    size = ftell(fd);
    rewind(fd);
    
    	if(fd < 0)
    	{
    	printf("%s", strerror(errno));
    	exit(EXIT_FAILURE);
    	}
    
            if(fd == NULL)
            {
            printf("%s. FD(NULL)\n", strerror(errno));
            exit(EXIT_FAILURE);
            }
            	else if(fd)
    		{
    
    			while(count < size)
    			{
    			
    				if((fread(buffer, sizeof(buffer), 1, fd)) != '\0')
    				{	
    					fread(buffer, sizeof(buffer), 1, fd);
    				}
    			
    				if (buffer[strlen(buffer) -1] == '\n')						
    				buffer[strlen(buffer)-1] = '\0';
    
    			count++;
    			}
    				
    				writefd = write(sockfd, buffer, strlen(buffer));
    	
    				        if(writefd <= 0)
    	        			{
    	        			printf("%s. WRITE(-1).\n", strerror(errno));
    	        			exit(EXIT_FAILURE);
    	        			}
    		}
    
    if((readfd = read(sockfd, buffer, sizeof(buffer))) < 0);
            {
            fprintf(stderr, "Error reading message from %s\n", inet_ntoa(cli_addr.sin_addr));
            printf("%s. READ(c)\n", strerror(errno));
            exit(0);
            }
    
    //Test to see if the buffer is blank. Uncomment to test.
            if(readfd == 0)
            {
            printf("Null buffer. READ(0)\n");
            }
    
                    else 
                    {
                    fprintf(stdout, "%s", buffer);
                    }
    
    }
    
    close(sockfd);
    
    return 0;
    }

  10. #10
    and the hat of wrongness Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    32,451
    Well you could work on your indentation -> SourceForge.net: Indentation - cpwiki
    Annonymous likes this.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.
    I support http://www.ukip.org/ as the first necessary step to a free Europe.

  11. #11
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Definitely pick a more normal indentation style -- there are about 10 of them here:

    Indent style - Wikipedia, the free encyclopedia

    Code:
    		if(fd < 0)
    		{
    			printf("%s", strerror(errno));
    			exit(EXIT_FAILURE);
    		}
    This is wrong, since fd is actually a FILE* and cannot be <0. BTW: "fd" is usually short for "file descriptor", which is an int used by the "lower level" functions such as open() and read() -- and socket(). FILE pointers are not file descriptors. They are sometimes called handles, so a parallel to fd would be fh.

    Fortunately you do test for NULL after that, which is what fd would be if fopen() failed.

    Here's another strange error test:
    Code:
    		if((fread(buffer, sizeof(buffer), 1, fd)) != '\0')
    		{
    			fread(buffer, sizeof(buffer), 1, fd);
    		}
    '\0' aka the null terminator is a char equal to 0. So you are saying, if fread() does not read nothing, to fill buffer again. Presumably this means chunks of the file end up missing...

    I think you should save the return value of the first fread call, and forget the second one. Then use it here:

    Code:
    	writefd = write(sockfd, buffer, strlen(buffer));
    In place of strlen(), which is a bad move:
    a) if the file is not a text file, since fread() may have read data including zero bytes, but strlen() counts them as the null terminator.
    b) if the file is a text file, because fread does not add a '\0', and if there is not one in buffer, strlen(buffer) will go out of bounds and possibly cause a seg fault.

    In general when handling files for purposes like this, don't use any string functions, or look for newlines or null terminators, etc. Treat them as binary data -- it will be fine, even if it is literally a txt file. You also do not have to add a '\0' unless that is understood as part of your transmission protocol. Remember, '\0' is used by C internally as a string delimiter. Actual text files should not, by definition, contain any '\0', and binary files may contain them anywhere.

    So, instead, you take the return value of fread(), which is the number of bytes actually read into buffer, and use that as the number of bytes for write() to write from buffer, meaning you are reading and writing in the same loop. You also increment "count" by the return value, which will make your while condition work properly:

    Code:
    		int bytes, sent, cur;
    		while(count < size) {
    			bytes = fread(buffer, sizeof(buffer), 1, fd);
    			if (!bytes) break; // complete
    			sent = 0;
    			while (sent < bytes) {
    				cur = write(sockfd, buffer + sent, bytes - sent);
    				if (!cur) { 
    					// handle disconnection
    				} else if (cur < 0) {
    					// handle write error
    				}
    				sent += cur;
    			}
    			count += bytes;
    		}
    Notice there's a inner loop to make sure write() gets everything done, which can be an issue for inet sockets.

    Code:
    		if(readfd == 0)
    If read/recv() or send/write() on a socket returns 0, it almost always indicates the other end has disconnected. I say "almost" because this seems to be undocumented, but I have never seen it happen for any other reason. Other errors (which can also include disconnections) are of course -1.
    Last edited by MK27; 01-07-2012 at 10:01 AM.
    Salem likes this.
    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

  12. #12
    Registered User Annonymous's Avatar
    Join Date
    Apr 2011
    Location
    Jackson, New Jersey, United States
    Posts
    302
    @Salem, A lot of people say my indentation is poor but i find it helps me sort through my code with ease! Inside every block, i use a tab for every condition. 1 tab for the first if or while, 2 tabs for the else/else following the previous if statement, and so on. I will have a look though. Thanks for the input.

    @MK27, to my understanding; I know an fd is a pointer to a file. I figure that i could compare it to less than 0 because if there are no files to open it would return less than 0. Though, now i see that is what if fd == NULL is for. Kind of embarrassed now! <Shakes head in shame>. I do know the difference between a FD and a FH.

    I also know that '\0' is a null terminator, an equivalent of 0, an int. Like a condition that uses EOF, it returns '\0' or 0, upon EOF. Which cannot be used with fgets. Since fgets returns a pointer to a file, aka an FH, and EOF returns an int. I used it with fread because i thought that the condition i set "meant", that as long as the file does not equal EOF, populate the buffer with the data from the file.

    I also thought that i am supposed to use strlen with the write function because i dont wanna send that padded garbage after the actual data. Am i wrong?? I see it is bad to use it with fread tho. Is there a work around? A more proper way to do this?

    I def have a long way to go though!

    Here is the changes i made:

    Code:
    for( ; ; ) 
    {
    int count = 0, bytes;
    
    FILE *fd;
    fd = fopen(argv[3], "r");
    
    fseek(fd, 0, SEEK_END);
    size = ftell(fd);
    rewind(fd);
    
            if(fd == NULL)
            {
            printf("%s. FD(NULL)\n", strerror(errno));
            exit(EXIT_FAILURE);
            }
            	else if(fd)
    		{
    
    			if(count < size)
    			{
    			bytes = fread(buffer, sizeof(buffer), 1, fd);
    			count++;
    			}
    				else if(!bytes)
    				{
    				printf("%s. FREAD ERROR.\n", strerror(errno));
    				exit(EXIT_FAILURE);
    				}
    
    			if(buffer[strlen(buffer) -1] == '\n')						
    			buffer[strlen(buffer)-1] = '\0';
    
    		}
    				
    	writefd = write(sockfd, buffer, strlen(buffer));
    	if(writefd == 0)
    	{
    	printf("Nothing was written.\n");
    	break;
    	}
    
    memset(buffer, 0, sizeof(buffer));
    readfd = read(sockfd, buffer, sizeof(buffer));
    	if(readfd < 0)
    	{
            fprintf(stderr, "Error reading message from %s\n", inet_ntoa(cli_addr.sin_addr));
            printf("%s. READ(c)\n", strerror(errno));
            exit(0);
            }
    
    //Test to see if the buffer is blank.
            if(readfd == 0)
            {
            printf("Null buffer. READ(0)\n");
    	exit(EXIT_SUCCESS);
            }
    
    }
    Next i will implement the 4 byte header concept y'all suggested, and gradually add to it.

  13. #13
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    There's a nasty mistake in the code I posted in #11, explained below. I think it's important for you to read this whole post carefully for some other reasons as well.

    Quote Originally Posted by Annonymous View Post
    @MK27, to my understanding; I know an fd is a pointer to a file. the difference between a FD and a FH.
    Okay, so to be clear and definitive: in C a file descriptor is an int, and a file "handle" (aka, a file stream) is a FILE pointer. However, while all FILE pointers are file streams, not all ints are file descriptors. Keep that in mind for a minute...

    I also know that '\0' is a null terminator, an equivalent of 0, an int. Like a condition that uses EOF, it returns '\0' or 0, upon EOF. Which cannot be used with fgets. Since fgets returns a pointer to a file, aka an FH, and EOF returns an int. I used it with fread because i thought that the condition i set "meant", that as long as the file does not equal EOF, populate the buffer with the data from the file.
    Couple things. I noticed in the code you used "fd" as a suffix on some variable names (like "writefd") for storing the return value of file operations, like write(). But those are not fd's at all, and have nothing to do with them. Just because a function returns an int and operates on files does not make that int a file descriptor, so you should stop labelling the variable that way because it contributes to a significant misunderstanding.

    That said, go back and read your documentation WRT the return value of fread() and write(). In fact, it's not even an int, it's a ssize_t or size_t which is subtly different (but automatically converted and for most purposes synonymous with int or unsigned int). Also note that while fread()/fwrite operate on file streams whereas read()/write()/recv()/send() operate on file descriptors, the return value for all those functions is the same: it is the amount of data actually written or read. There is one big difference: for the "f" (stream) functions the unit is "number of objects", for the lower level functions it is number of bytes. And there is one minor difference: size_t is an unsigned type, so the "f" (file stream) functions don't ever return -1:

    Quote Originally Posted by man fread
    RETURN VALUE
    fread() and fwrite() return the number of items successfully read or written (i.e., not the number of characters). If an error occurs, or the end-of-file is reached, the return value is a short item count (or zero).

    fread() does not distinguish between end-of-file and error, and callers must use feof(3) and ferror(3) to determine which occurred.
    Okay, so that point about the return value of all the various file reading/writing/transmitting functions should be easy to remember: they are all the same, and they are not file descriptors. They return the amount of data involved, which may be different than the amount you asked to be involved. And zero may indicate an error, eof, or in the case of sockets, a disconnection. The low level (no "f") functions also return -1 for certain errors.

    I also thought that i am supposed to use strlen with the write function because i dont wanna send that padded garbage after the actual data. Am i wrong?? I see it is bad to use it with fread tho.
    Yep, it is bad to use with fread() because fread() is not string, aka text, oriented. WRT file transfer, like I said before, it does not matter whether a file is text or "binary". It doesn't matter at all what is in the file. You are just breaking it into chunks and transmitting it.

    That means you need to keep track of the actual amount of non-garbage data at the beginning of the data manually -- there is no function that will find it for you. That's why the return values just mentioned are so important.

    So don't use strlen there! Again, that is a problem:

    Quote Originally Posted by MK27
    a) if the file is not a text file, since fread() may have read data including zero bytes, but strlen() counts them as the null terminator.
    b) if the file is a text file, because fread does not add a '\0', and if there is not one in buffer, strlen(buffer) will go out of bounds and possibly cause a seg fault.
    Is there a work around? A more proper way to do this?
    Yep, that's the code I gave you in post #11. More or less, because there is a big mistake in it, lol, related to the return value. I don't use the stream functions much.

    bytes = fread(buffer, sizeof(buffer), 1, fd);
    Whoops! Fread(), as just discussed, returns the number of objects, not the number of bytes. The number of bytes in an object is determined by the second arg. So we could subsequently do this:

    Code:
        bytes *= sizeof(buffer);
    But this is not such a good idea, because:

    Quote Originally Posted by GNU Reference
    If fread encounters end of file in the middle of an object, it returns the number of complete objects read, and discards the partial object.
    Ie, unless the file is a perfect multiple of sizeof(buffer), you'll lose some.

    Instead, we should use an object size of 1, and make the number of desired objects sizeof(buffer):

    Code:
        bytes = fread(buffer, 1, sizeof(buffer), fd);
    Now "bytes" will actually be the amount of data measured in bytes, which is what we need for use with write. Using the f "stream" functions on sockets is a bad idea because of that object size issue; non-local sockets can easily return less than they were supposed to.

    You don't have to do it exactly this way, but you do need to follow the general principle WRT to keeping exact track of the data volume via the return values from your read and write functions. There are no other choices!
    Last edited by MK27; 01-08-2012 at 09:12 AM.
    Salem and Annonymous like this.
    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

  14. #14
    Registered User Annonymous's Avatar
    Join Date
    Apr 2011
    Location
    Jackson, New Jersey, United States
    Posts
    302
    Thats a lot to take in at once MK27. I am going to give it a break for bit since i have been at my laptop for days without a break. And i feel groggy and weird! I will re-read that when i come back to the FTP client and have another crack at it and study what i must. Thank you

  15. #15
    Registered User Annonymous's Avatar
    Join Date
    Apr 2011
    Location
    Jackson, New Jersey, United States
    Posts
    302
    Back at it and i have made some mods to the server. I am reading 4 bytes of data in at a time. BUT....I am having a problem. The client reads in the data from the the specified file to a buffer and then writes it to the server and completes the write function and waits for data with the read call. The server reads in 4 bytes of data until there is none left but makes an extra call to read and hangs unless i manually close from the client.

    I have tried a bunch of things. Like adding a new line char to the buffer(client-side) before sending. Using conditions such as if readfd != '\n' or '\0' but it seems the newline being read in is actually being treated as a string literal instead of a char constant. If i trim the trailing newline and replace it with a '\0', same thing. It treats the '\0' as a string literal.

    i ran an strace and and took a pic to give you a better visual. Attachment 11372

    heres the server code:

    Code:
    for( ; ; ) {
    int count = 0, rc;
    int recieved = 4;
    char buffer[4];
    memset(buffer, '\0', sizeof(buffer));
    
    for( ; ; )
    {
    	readfd = read(newsockfd, buffer, sizeof(buffer));
    	if(readfd < 0)
    	{ 
    	fprintf(stderr, "%s. READ(s)\n", strerror(errno)); 
    	exit(1);
    	} 
    
    	//Test to see if the buffer is blank.
    	if(readfd == 0)
    	{
    	printf("Null buffer. READ()\n");
    	exit(1);
    	}
    
    	/*if(readfd == '\0')
    	{
    	fprintf(newline, sizeof(newline));
    	}*/
    
    	fprintf(fp, "%s", buffer);	//fprintf must be inside the while loop or it will print nothing.
    
    count += recieved;
    rc++;
    printf("%d.\n", rc);
    }		
    
    	memset(buffer, 0, sizeof(buffer));
    	writefd = write(newsockfd, buffer, strlen(buffer));
    	if(writefd < 0)
    	{
    	printf("%s. WRITE(s)\n", strerror(errno));
    	exit(EXIT_FAILURE);
    	}
    
    	if(writefd == 0)
    	{
    	printf("Nothing was written.\n");
    	exit(0);
    	}
    
    }
    client code:

    Code:
    for( ; ; ) 
    {
    long unsigned int count = 0, bytes;
    FILE *fd;
    fd = fopen(argv[3], "r");
    
    fseek(fd, 0, SEEK_END);
    long unsigned int size = (long unsigned int)ftell(fd);
    rewind(fd);
    //printf("Sizeof(file) == %lu.\n", size);
    
    	char buffer[size];
    
            if(fd == NULL)
            {
            printf("%s. FD(NULL)\n", strerror(errno));
            exit(EXIT_FAILURE);
            }
            	else if(fd)
    		{
    		
    			if(count < size)
    			{
    			bytes = fread(buffer, 1, sizeof(buffer), fd);			
    			count++;
    			}
    
    				else if(!bytes)
    				{
    				printf("%s. FREAD ERROR.\n", strerror(errno));
    				exit(EXIT_FAILURE);
    				}
    			//Trim new line char. Doesn't matter if the trim is done inside the else if(fd) scope or out.
    			//You will acheive the same results.
    			//Without the trim, the file will print the char constant n. 
    			if(buffer[strlen(buffer) -1] == '\n')						
    			buffer[strlen(buffer)-1] = '\0';
    
    		}
    	
    	writefd = write(sockfd, buffer, sizeof(buffer));
    	if(writefd == 0)
    	{
    	printf("%s", strerror(errno));
    	printf("Nothing was written.\n");
    	break;
    	}
    
    memset(buffer, 0, sizeof(buffer));
    readfd = read(sockfd, buffer, sizeof(buffer));
    	if(readfd < 0)
    	{
            fprintf(stderr, "Error reading message from %s\n", inet_ntoa(cli_addr.sin_addr));
            printf("%s. READ(c)\n", strerror(errno));
            exit(0);
            }
    
    //Test to see if the buffer is blank.
            if(readfd == 0)
            {
            printf("Null buffer. READ(0)\n");
    	exit(EXIT_SUCCESS);
            }
    
    }
    I figure i could get the size of the file by setting the conditions in the for loop on the server but the problem is that i will not know the size of the file until the loop is complete.
    Last edited by Annonymous; 01-18-2012 at 06:25 PM.

Page 1 of 2 12 LastLast
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. server/client trouble yet again lol
    By Annonymous in forum Networking/Device Communication
    Replies: 8
    Last Post: 11-14-2011, 11:51 AM
  2. Connection between proxy server and the server
    By vbx_wx in forum Networking/Device Communication
    Replies: 2
    Last Post: 02-07-2011, 12:51 PM
  3. Send integers to server and server can read them?
    By rahul.hbk007 in forum C Programming
    Replies: 7
    Last Post: 05-02-2010, 10:14 AM
  4. C#: Server.Execute() and Server.Transfer()
    By Grayson_Peddie in forum Networking/Device Communication
    Replies: 3
    Last Post: 09-24-2003, 06:50 PM

Tags for this Thread


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21