Solved

send file

Posted on 2011-03-04
62
443 Views
Last Modified: 2012-06-27
I am sending a file from client to server by partition the file small part which size is 2048 and send each part . Below is my code. Please advise. tks.

FILE *fp;
       fp= fopen(t.c_str(),"r");// t is the filename string
       if(fp == NULL)
       {
            printf("error to open %s",t.c_str());
            exit(1);
       }
       fseek(fp, 0, SEEK_END);
       int size = ftell(fp);
       rewind(fp);
       int count = size/2048;
       int remainder = size %2048;
     
       char * buffer = (char*)malloc(sizeof(char) *size);
       char *p;
       p= buffer;

       // copy the file into the buffer:
       int result = fread (buffer,1,size,fp);
       
       if (result != size)
       {
            printf(" Reading error",stderr);
       }
       
       if( count >= 2048)
       {
             for( int i= 0; i < count;i++)
             {
                  send(sock, p, 2048,0);
                  p = p+2048;
             }
       
             //send the remainder trunk
             send(sock, p, remainder, 0);
       }
       else
       {
             send(sock, p, size, 0);
       }
     

0
Comment
Question by:BeginToLearn
  • 31
  • 22
  • 9
62 Comments
 
LVL 53

Assisted Solution

by:Infinity08
Infinity08 earned 80 total points
ID: 35034831
>>        if( count >= 2048)

You probably meant :

          if( size >= 2048)


Other than that, could you be more specific regarding what you need advice about ?
0
 

Author Comment

by:BeginToLearn
ID: 35034861
can you show me how to implement it by using struct buf? i know we can use st_size to get the file size. I favor for struct stat because later i will need to use timestamp. Thanks.
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 35034866
>> can you show me how to implement it by using struct buf?

What is struct buf ?
0
 

Author Comment

by:BeginToLearn
ID: 35034867
and using struct stat buf only save steps on calculating file size huh?
0
 

Author Comment

by:BeginToLearn
ID: 35034869
struct stat buf;
       stat(t, &buf);
       size_t sz = buf.st_size;

sorry mistyping
0
 
LVL 32

Expert Comment

by:sarabande
ID: 35034876
the file size easier can be get by stat function

#include <sys/stat.h>

   struct stat fileinfo;
   if (stat((t.c_str(), &fileinfo) != 0)
       return errno;   // file doesn't exist

   int size = fileinfo.st_size;

Sara
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 35034881
Ah, you mean struct stat.

Yes, you can use the stat function on the file to obtain a variety of information about the file :

        #include <sys/types.h>
        #include <sys/stat.h>
        #include <unistd.h>

        struct stat file_info;
        if (stat("/path/to/file", &file_info) != 0) {
            /* oops : error occurred (errno) : handle this */
        }

For more information, just check the manual page for stat :

        man stat
0
 

Author Comment

by:BeginToLearn
ID: 35034884
how about the rest of sending each trunk ? are they same? i just wan to shift more work to compiler :)
0
 
LVL 32

Expert Comment

by:sarabande
ID: 35034885
oh, you asked the question while i was typing the answer :)

Sara
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 35034893
There is no standard function that splits up data into chunks and sends those chunks. You'll need to do that yourself.
0
 

Author Comment

by:BeginToLearn
ID: 35034901
tks a lot . i gonna offline for 8 hrs.srry.
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 35034906
No problem. Take your time :)

If you have any further questions about this, we'll still be here.
0
 
LVL 32

Expert Comment

by:sarabande
ID: 35034930
you may try

       if( size > 0)
       {
             // count is the number of full chunks
             for( int i= 0; i < count;i++)
             {
                  send(sock, p, 2048,0);
                  p = p+2048;
             }
       
             //send the remainder trunk
             if (remainder > 0)
                 send(sock, p, remainder, 0);
       }


Sara
0
 

Author Comment

by:BeginToLearn
ID: 35038092
I think of this issue for later on. Because I gonna send many files which may have MB or GB size file and using time attribute . For example. a file is 3 GB. So the malloc and struct stat will need to allocate twice of 3GB memory.So my program will have a high chance to crash.
 That's why I want to find a way to use memory efficient hihi.
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 35038387
>> For example. a file is 3 GB. So the malloc and struct stat will need to allocate twice of 3GB memory.So my program will have a high chance to crash.

Ah, well, you don't need to read the entire file in memory at the same time.

You can read the data from the file one chunk at a time, just like you're sending it one chunk at a time.

Just do :

        fread (buffer,1,2048,fp);

(or whatever you want your chunk size to be) in the same loop where you do the send.
0
 

Author Comment

by:BeginToLearn
ID: 35041907
i didn't think about this " You can read the data from the file one chunk at a time, just like you're sending it one chunk at a time." tks.let me modify it and work on server side then ask question again :)
0
 

Author Comment

by:BeginToLearn
ID: 35046570
Do we need to send the file name and size from client to server? then create open that filename  and use file size  in for loop to write  all received trunks in to that file? Please advise. Thanks.
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 35047032
You don't need to, but you can. It all depends on the communication protocol you use/created for sending files.
0
 

Author Comment

by:BeginToLearn
ID: 35047187
Can u take a look at my code bc I dont understand ur advise welll
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 35047202
What code are you referring to ?

What advice are you referring to ?

What about it is it that you don't understand ?
0
 

Author Comment

by:BeginToLearn
ID: 35047288
You said it d depend on protocol.can u elaborate more?
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 35047354
>> You said it d depend on protocol.can u elaborate more?

It depends on how you decide to send the file to the other side. If you decide to send the file name and file size, then you should send them. If you decide to do it otherwise (without sending the filename and size), then you should not send them.

It's up to you.
0
 

Author Comment

by:BeginToLearn
ID: 35047500
which one way is more flexible and easier to develop and change later on ? can you show me example for each way ( or link)? tks a lot.
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 35047666
Sending the file size first will help the other side to allocate enough memory if the other side needs that information. If you're just streaming the received data into a file, there's probably no need for this information.

Sending the filename will allow the other side to use the same filename for the file.

So, again : it all depends on what you want to do. One is not necessarily easier or more flexible - you just have to make a choice about how you want to do things.
0
 

Author Comment

by:BeginToLearn
ID: 35048081
Do you have any example?
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 35048271
What do you mean ? An example of what ?

You decide on how you want to send the file (ie. the transmission/communication protocol), and then implement that.

From what I gather, you're already sending the file in chunks, so there's not much more to it than that. Just receive the chunks on the other end, and re-assemble the file. And that's it.
0
 

Author Comment

by:BeginToLearn
ID: 35049156
Oh what I meant is without file name and its size,how the server know wgen it has receive enough number of trunks for each file
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 35053772
>> Oh what I meant is without file name and its size,how the server know wgen it has receive enough number of trunks for each file

When you stop sending.
When you close the connection.
When you send a specific "command".
etc.

Or you can just send the file size ;)

It's up to you.
0
 

Author Comment

by:BeginToLearn
ID: 35054212
I need to get filename, add a space, and its filesize. Server will receive it and parse to get filesize. Then apply same formula and for loop similar to the one on  client side. for each trunk receive, it will be appended on the file. Am i right? hihi
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 35054275
That sounds like a plan :)
0
 

Author Comment

by:BeginToLearn
ID: 35054314
is that plan workable? hihi
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 53

Expert Comment

by:Infinity08
ID: 35054353
I wouldn't call it a plan if it wasn't ;)
0
 

Author Comment

by:BeginToLearn
ID: 35054510
cool. I gonna implement it tomorrow :)
0
 
LVL 32

Expert Comment

by:sarabande
ID: 35054855
i would suggest you first send size of filename as a 32bit integer. then the filename. then the filesize as 64bit integer. then the data.

don't use space char after filename for size check. better always make a pair of length and data.

if the filesize can be 3GB you can't use signed 32-bit integer as in the code you posted.

if the filesize can be 4GB or more you can't use (normal) stat function which only has 32bit integer for size. some compilers already use 64-bit integers in struct stat. others have functions stat64 or fstat64. same applies for fseek, ftell, fseekpos.

Sara
0
 

Author Comment

by:BeginToLearn
ID: 35060079
write now i only focus on 32 bit . I have "Segmentation fault" at server side while writing trunk to file. So I need help :)
( my program is take the last file on the <string>list and send trunks of that  file to server side)    client.c server.c
0
 

Author Comment

by:BeginToLearn
ID: 35066574
after i sent the file name, server could receive it . then it send a trunk of file, server got segmentation fault. It could display the trunk before sending. However, receiving got x) and crash
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 35067047
Where does the segmentation fault occur ?
What was the output you got ?

Are you aware that the first read you do reads 2048 bytes ? ie. it probably contains the filename, the filesize, and a part of the file.
0
 

Author Comment

by:BeginToLearn
ID: 35067100
segmentation fault occurs right after read() in server. it read x) when i run debugger. In order to avoid client open a file to send and server append the file , i open the filename with its size such as "test.c 39".
 It could read perfect the trunk before sending. Something is wrong with receiving the trunk. However, the string of filename, space, and filesize was send sucessfully
0
 

Author Comment

by:BeginToLearn
ID: 35067106
btw, i have updated some parts in my code. so the previous one doesn't reflect current change.
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 35067141
>> segmentation fault occurs right after read()

There are more than one read in that code. Which read are you referring to ?


>>  btw, i have updated some parts in my code. so the previous one doesn't reflect current change.

Then you might want to post that modified code ;)


Did you also see this comment in my previous post :

>> Are you aware that the first read you do reads 2048 bytes ? ie. it probably contains the filename, the filesize, and a part of the file.
0
 

Author Comment

by:BeginToLearn
ID: 35067179
well for testing purpose, it didn't read 2048 bytes at the first time because the file size is less than 2048.
I use
     printf("buffer is before sending : \n%s\n",buffer);
   
to reaffirm trunk content. It is ok.
and  
    printf("buffer is after receiving : \n%s\n",buffer);
--> segmentation fault.

     
here is client.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>


#include <string>
#include <iostream>
#include <list>
#include <iterator>
#include <sstream>

using namespace std;



typedef int SOCKET;

#define PORT 3490



void error(const char *msg)
{
    perror(msg);
    exit(0);
}


void list_all_files ( const string& sStartDir, list<string>& lstFound) {

   //cout << "checking " << sStartDir.c_str () << endl;

   DIR* pDir = opendir ( sStartDir.c_str ());

   if ( !pDir) return;

   dirent* pEntry;

   while ( pEntry = readdir ( pDir)) {

    // cout << "found " << pEntry->d_name << endl;

       if ( DT_DIR & pEntry->d_type && strcmp ( pEntry->d_name, ".") && strcmp ( pEntry->d_name, "..")) {

           string sSubDir = sStartDir + string ( "/") + string ( pEntry->d_name);

           list_all_files ( sSubDir, lstFound) ;

       }

       string sFound = sStartDir + string ( "/") + string ( pEntry->d_name);

       lstFound.push_back ( sFound);
   }
}

void sendFile ( SOCKET sock, list<string>& myList)
{
       cout<<" in sendFile myList size: "<<myList.size()<<endl;
     
       list<string>::iterator ptr;
       
       string t;
       
       for( ptr =myList.begin(); ptr !=myList.end(); ptr++)
       {  
              t = *ptr;
              //cout<<"t is :"<<t<<endl;
       }
         
       /*
       we will use struct stat later on because it has file timestamp attribute !!!!!!!
       struct stat buf;
       stat(t, &buf);
       size_t sz = buf.st_size; // a faster way to get filesize !!!!!!!!!!!
       
       char filechunk[2048];
       size_t count = sz/2048;
       size_t remainder = sz%2048;

       }*/

     
       
       FILE *fp;
       fp= fopen(t.c_str(),"r");// t is the filename string
       if(fp == NULL)
       {
            printf("error to open %s",t.c_str());
            exit(1);
       }
       // determine file size
       fseek(fp, 0, SEEK_END);
       int size = ftell(fp);
       rewind(fp);
       
        //using the last filename to test idea
      // add a " " then its filesize to filename then send it to server side
      // so server side can apply same formula while dealing with trunks.
      cout<<"the last t is :"<<t<<endl;

      std::stringstream tmp;
      tmp << size;
      t= t.append(" ");
      t= t.append(tmp.str());
      cout<<"t after append file size is :"<<t<<endl;
     
      char *pch = (char*)malloc(sizeof(char) *t.length() +1);
      memset(pch,sizeof(char)*t.length(),'\0');
      strcpy(pch, t.c_str());

      send(sock, pch,t.size(),0);

       // calculate  number of trunks
       int count = size/2048;
       int remainder = size %2048;
     
       char * buffer ;
       char *p;
       p= buffer;

       // read in trunk and send trunk of each file until done fo each file and move on
       int result;
       if( size >= 2048)
       {
             for( int i= 0; i < count;i++)
             {
                  buffer= (char*)malloc(sizeof(char) *2048);
                  result= fread (buffer,1,2048,fp);
                  if (result != size)
                  {
                        printf(" Reading error",stderr);
                        exit(1);
                  }
                 
                  send(sock, p, 2048,0);
             }
             
             //send the remainder trunk
             buffer= (char*)malloc(sizeof(char) *remainder);
             result= fread (buffer,1,remainder,fp);
             if (result != remainder)
             {
                   printf(" Reading error",stderr);
                   exit(1);
             }
             send(sock, p, remainder, 0);
       }
       else
       {
             buffer= (char*)malloc(sizeof(char) *size);
             result= fread (buffer,1,size,fp);
             if (result != size)
             {
                   printf(" Reading error",stderr);
                   exit(1);
             }
             printf("buffer is before sending : \n%s\n",buffer);
             strcpy(buffer, "hi");
             send(sock, p, size, 0);
       }
       fclose(fp);
     
 
       
}


int sendFileProcess(SOCKET sock)
{

       char cwd[1024];
       list<string> myList;

       memset ( cwd, '\0',sizeof(cwd));
       
        if (getcwd(cwd, sizeof(cwd)) != NULL)
      {
           printf("Current working dir: %s\n", cwd);
        }      
      else
           perror("getcwd() error");
      /*
       //display all file names in dir and subdir
       DIR *mydir = opendir(cwd);
       struct dirent *entry = NULL;
       while((entry = readdir(mydir)))
       {
            printf("entry->d_name: %s\n", entry->d_name);
       }
       cout<<endl;
       //closedir(mydir);
        */
       
       list_all_files ( cwd, myList);// this function will get all filename in a directory
             
       sendFile(sock, myList);
 
     return 1;
}

int main(int argc, char *argv[])
{
    int sockfd, portno, n;
    struct sockaddr_in serv_addr;
    struct hostent *server;

    char buffer[256];


    portno = PORT;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
        error("ERROR opening socket");

    server = gethostbyname("ubuntu");

    if (server == NULL) {
        fprintf(stderr,"ERROR, no such host\n");
        exit(0);
    }

    bzero((char *) &serv_addr, sizeof(serv_addr));

    serv_addr.sin_family = AF_INET;

    bcopy((char *)server->h_addr,
         (char *)&serv_addr.sin_addr.s_addr,
         server->h_length);

    serv_addr.sin_port = htons(portno);
    if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
        error("ERROR connecting");

   
    sendFileProcess(sockfd);

    printf("Please enter the message: ");
    bzero(buffer,256);
    fgets(buffer,255,stdin);

    n = write(sockfd,buffer,strlen(buffer));
    if (n < 0)
         error("ERROR writing to socket");
   
    bzero(buffer,256);
    n = read(sockfd,buffer,255);
    if (n < 0)
         error("ERROR reading from socket");

    printf("client: %s\n",buffer);
    int t;
      if(( t= close(sockfd))== -1)
            printf("t is %d\n",t);
    return 0;
}


--------------


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define PORT 3490

void error(const char *msg)
{
      perror(msg);
          exit(1);
}

int main(int argc, char *argv[])
{
           int sockfd, newsockfd, portno;
           socklen_t clilen;
           char buffer[2048]="\0", buffer2[2048]="\0";
           struct sockaddr_in serv_addr, cli_addr;
      int n;
        int yes = 1;
   

      sockfd = socket(AF_INET, SOCK_STREAM, 0);
           if (sockfd < 0)
              error("ERROR opening socket");
           bzero((char *) &serv_addr, sizeof(serv_addr));
           

      portno = PORT;
      if(setsockopt( sockfd, SOL_SOCKET,SO_REUSEADDR, &yes, sizeof(int))== -1) {
            perror("setsockopt");
            exit(1);
        }

           serv_addr.sin_family = AF_INET;
           serv_addr.sin_addr.s_addr = INADDR_ANY;

           serv_addr.sin_port = htons(portno);
           
      if (bind(sockfd, (struct sockaddr *) &serv_addr,
              sizeof(serv_addr)) < 0)
              error("ERROR on binding!!!");
       
        listen(sockfd,5);
        clilen = sizeof(cli_addr);
     
      newsockfd = accept(sockfd,
                 (struct sockaddr *) &cli_addr,
                 &clilen);
           if (newsockfd < 0)
                error("ERROR on accept");
           bzero(buffer,2048);

           n = read(newsockfd,buffer,2048);
       

           if (n < 0) error("ERROR reading from socket");

           printf("Here is the message from client: %s\n",buffer);
       
        strcpy(buffer2,buffer);      
   
        //buffer contains "filename space itssize"
        // so we need to parse the buffer to get filename and its size in order to open file and write all trunks to file
       
        char seps[]= " ";
        char *token;
        char filename[300]="\0";
        char filesize[300]="\0";
       
        // establish string and get the first token
        token = strtok( buffer, seps);

        strcpy(filename,token);
        printf( "filename= %s\n",filename);

        printf( "token= %s\n",token);
        token= strtok( NULL,seps);
        strcpy( filesize, token);
        printf( "filesize= %s\n",filesize);


        FILE *fp;
        fp = fopen(buffer2, "a");// for testing purpose instead filename, just use buffer2( filename with space and its size)
        if( fp = NULL)
        {
              printf("failed to open %s to append\n",filename);
        }
        int size = atoi(filesize);
        printf("size is %d\n",size);

        // calculate  number of trunks
       int count = size/2048;
       int remainder = size %2048;
       
       // read trunks and write/append trunk of each file
       int result;
        memset(buffer,2048,'\0');
       if( size >= 2048)
       {
             for( int i= 0; i < count;i++)
             {
                  read(newsockfd,buffer,2048);
                 
                  result= fwrite (buffer,1,2048,fp);
                  if (result != 2048)
                  {
                        printf(" Writing error",stderr);
                        exit(1);
                  }
             }
             
             //remainder  of trunk
             read(newsockfd,buffer,remainder);
             result= fwrite (buffer,1,remainder,fp);
             if (result != remainder)
             {
                   printf(" Writing error",stderr);
                   exit(1);
             }
       }
       else
       {
             read(newsockfd,buffer,remainder);
             printf("buffer is after receiving : \n%s\n",buffer);
             result= fwrite (buffer,1,remainder,fp);
             if (result != remainder)
             {
                   printf(" Writing error",stderr);
                   exit(1);
             }
       }
       fclose(fp);
     
       




           n = write(newsockfd,"Message from server",18);
           if (n < 0) error("ERROR writing to socket");

      int t1, t2;
           if( t1= close(newsockfd) ==-1)
            error("ERROR in close newsockfd");
      printf("t1 is %d\n", t1);

            if( t2= close(sockfd) == -1)
            error("ERROR in close sockfd");
      printf("t2 is %d\n", t2);
           return 0;
}
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 35067844
>> to reaffirm trunk content. It is ok.

That line stops showing the buffer as soon as it encounters a '\0' character. So it does NOT guarantee that there's nothing else in the buffer.

Check the return value of read, to see how many bytes it actually read, and then show that many bytes from the buffer.
0
 

Author Comment

by:BeginToLearn
ID: 35070831
t after append file size is :/home/ubuntu/program/test.c 319
number of bytes is read into buffer before sending is 319
--> it is correct and match with the file size on directory.
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 35070895
>> --> it is correct and match with the file size on directory.

But do the contents of the file match ?
0
 

Author Comment

by:BeginToLearn
ID: 35070939
i can see they match clearly :)
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 35070971
Ok, then it seems you got lucky. Do check the return value of read though every time you use it.


You'll need to find out where exactly the segmentation fault occurs (you can run the code in a debugger eg.), and what the relevant variables are set to.
0
 

Author Comment

by:BeginToLearn
ID: 35071002
at server side, after i added 1 line to display number of byte receiving
 
number of byte reading into buffer at receiving is 319
buffer is after receiving :
x)
Segmentation fault


0
 
LVL 53

Expert Comment

by:Infinity08
ID: 35071170
>>              printf("buffer is after receiving : \n%s\n",buffer);

You shouldn't use %s to show the buffer contents, because it'll keep on reading until a '\0' character is found, which might not be there.

Other than that, please follow my advice in http:#35070971
0
 

Author Comment

by:BeginToLearn
ID: 35071283
it crashes after receiving . When i run debugger, i can see the buffer content:

(gdb) print n
$2 = 319
(gdb) print buffer
$3 = "x)\016\000P\370s\267\200\035r\000\346\032\025\000\366\032\025\000\006\033\025\000\026\033\025\000&\033\025\000\066\033\025\000F\033\025\000V\033\025\000f\033\025\000\260,\030\000P\250\025\000\226\033\025\000\246\033\025\000\266\033\025\000\306\033\025\000\326\033\025\000\300\061\032\000\366\033\025\000\006\034\025\000\026\034\025\000&\034\025\000\066\034\025\000F\034\025\000V\034\025\000P\024\030\000v\034\025\000\206\034\025\000\226\034\025\000\246\034\025\000\266\034\025\000\306\034\025\000\326\034\025\000\346\034\025\000\366\034\025\000\006\035\025\000P\371.\000&\035\025\000\066\035\025\000F\035\025\000V\035\025\000f\035\025\000v\035\025\000\206\035\025\000\226\035\025\000\246\035\025\000\266\035\025\000\306\035\025\000\326\035\025\000\346\035\025\000\366\035\025\000\006\036\025\000\026\036\025\000&\036\025\000\260\312\031\000F\036\025\000\240a"...
0
 
LVL 32

Expert Comment

by:sarabande
ID: 35071469
each segmentation fault will produce a core file. when you are in debugger you can open the core file rather than debug the application. it then will point exactly to the statement that caused the crash. going up in the call stack then will show the line of your code if it isn't already your code but some system code.

Sara
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 35071534
>> it crashes after receiving

Right, we got that already.

But there's quite a bit of code after the receive.

And you'll also need to know the values of impacted variables in order to figure out what caused the crash.
0
 

Author Comment

by:BeginToLearn
ID: 35072007
after i enable core file to unlimited and issue command:
   gdb server core

I got those info:

ubuntu@ubuntu:~/program$ gdb server core
GNU gdb (GDB) 7.2-ubuntu
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/ubuntu/program/server...done.
[New Thread 1897]

warning: Can't read pathname for load map: Input/output error.
Reading symbols from /usr/lib/libstdc++.so.6...(no debugging symbols found)...done.
Loaded symbols for /usr/lib/libstdc++.so.6
Reading symbols from /lib/libm.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib/libm.so.6
Reading symbols from /lib/libgcc_s.so.1...(no debugging symbols found)...done.
Loaded symbols for /lib/libgcc_s.so.1
Reading symbols from /lib/libc.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib/ld-linux.so.2
Core was generated by `./server'.
Program terminated with signal 11, Segmentation fault.
#0  0x00eafb4c in fwrite () from /lib/libc.so.6
(gdb)

---> something is wrong with fwrite huh?
0
 
LVL 32

Accepted Solution

by:
sarabande earned 420 total points
ID: 35072132
i didn't found the crash but when looking at your code i strongly advise you to overwork it. there are so many incorrect or unnecessary parts, which don't lead to the crash but make the code badly readable and error-prone:

1. you included <string.h> twice

2. you included both <string.h> and <string>

for c++ the second is sufficient.

3. you defined PORT in multiple sources. better use a const int defined in one cpp and declare variable as extern in other cpp's (or in a header file included by all).

4. PORT number 3470 is relative low number. if you copied the code from somewhere you better use a new (randomly picked) number between 30000 and 60000. otherwise there is higher risk that port already was used.

5. in error routine you shouldn't exit with 0 (what means success)

6. if a function like list_all_files can fail it shouldn't simply return. either return error or exit (or throw exception).

7. when calling strcmp you should not test on true or false cause that is badly readable. instead compare with 0.

   ... && strcmp ( pEntry->d_name, ".") != 0

8. if an argument paassed by reference like list<string>& was not changed in a function, pass it as const list<string>& . that way you can much better see what is input and what is output.

9. in c++ code you should prefer operator 'new' over malloc.

10. the usage of sizeof(char) is unnecessary cause sizeof(char) == 1 by definition.

11. when using sizeof you should multiply it with all elements of an array. you did

  char *pch = (char*)malloc(sizeof(char) *t.length() +1);

where sizeof(char) was multiplied with t.length but it should be (t.length + 1).

12. if using memset you should initialize all elements and not only a part. you did

    memset(pch,sizeof(char)*t.length(),'\0');

but pch has size (t.length()+1).

13. you can't spare the memset if you do a strcpy after.

14. if you use a char pointer which always needs an allocation, you should do the allocation immediately,

     char * buffer = (char*)malloc(2048);

it makes no sense to do the malloc in the if and in the else branch separately.

in the part i mean you have an error!!!

first you define char pointers buffer and p

       char * buffer ;
       char *p;
       p= buffer;

after that, both buffer and p have some random value (both the same).

later you do the malloc where buffer gets a valid pointer.

but p is still invalid and you do

  send(sock, p, remainder, 0);  

for example, what could crash if p is NULL or not pointing to valid address.

15. if you use a char pointer which always has same allocation, you should use a fixed-sized char array instead.

   char buffer[2048] = { '\0' };

such arrays can be initialized with zeros what spares the memset or bzero at first time use.

16. if you use a char pointer you have to free it after use or you get memory leaking.

   char * p = (char*)malloc(2048);
   ....

   free(p);

I stop here though i am only at the beginning.

you should overwork your code and then post again.

Sara




   


0
 

Author Comment

by:BeginToLearn
ID: 35072181
let me go over the code and change those suggestion
0
 
LVL 32

Expert Comment

by:sarabande
ID: 35072192
in memset you have mixed up size and value. it must be

  memset(buffer, '\0', 2048);

the fwrite has a problem with your arguments. probably the buffer is corrupted somehow.

check all arguments in the debugger.

Sara
0
 

Author Comment

by:BeginToLearn
ID: 35072487
A little progress after i change the code at this sugestion

first you define char pointers buffer and p

       char * buffer ;
       char *p;
       p= buffer;

after that, both buffer and p have some random value (both the same).

later you do the malloc where buffer gets a valid pointer.

but p is still invalid and you do

  send(sock, p, remainder, 0);  

for example, what could crash if p is NULL or not pointing to valid address.

-->
It can receive the content now even though it still have segmentation fault
below in the update



-----

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <dirent.h>
#include <sys/stat.h>


#include <string>
#include <iostream>
#include <list>
#include <iterator>
#include <sstream>

using namespace std;



typedef int SOCKET;

#define PORT 50000



void error(const char *msg)
{
    perror(msg);
    exit(EXIT_FAILURE);
}


void list_all_files ( const string& sStartDir, list<string>& lstFound) {

   //cout << "checking " << sStartDir.c_str () << endl;

   DIR* pDir = opendir ( sStartDir.c_str ());

   if ( !pDir) return;

   dirent* pEntry;

   while ( pEntry = readdir ( pDir)) {

     cout << "found " << pEntry->d_name << endl;

       if ( DT_DIR & pEntry->d_type && strcmp ( pEntry->d_name, ".") && strcmp ( pEntry->d_name, "..") != 0) {

           string sSubDir = sStartDir + string ( "/") + string ( pEntry->d_name);

           list_all_files ( sSubDir, lstFound) ;

       }

       string sFound = sStartDir + string ( "/") + string ( pEntry->d_name);

       lstFound.push_back ( sFound);
   }
}

void sendFile ( SOCKET sock,  list<string>& myList)
{
       cout<<" in sendFile myList size: "<<myList.size()<<endl;
     
       list<string>::iterator ptr;
       
       string t;
       
       for( ptr =myList.begin(); ptr !=myList.end(); ptr++)
       {  
              t = *ptr;
              //cout<<"t is :"<<t<<endl;
       }
         
       /*
       we will use struct stat later on because it has file timestamp attribute !!!!!!!
       struct stat buf;
       stat(t, &buf);
       size_t sz = buf.st_size; // a faster way to get filesize !!!!!!!!!!!
       
       char filechunk[2048];
       size_t count = sz/2048;
       size_t remainder = sz%2048;

       }*/

     
       
       FILE *fp;
       fp= fopen(t.c_str(),"r");// t is the filename string
       if(fp == NULL)
       {
            printf("error to open %s",t.c_str());
            exit(1);
       }
       // determine file size
       fseek(fp, 0, SEEK_END);
       int size = ftell(fp);
       rewind(fp);
       
        //using the last filename to test idea
      // add a " " then its filesize to filename then send it to server side
      // so server side can apply same formula while dealing with trunks.
      cout<<"the last t is :"<<t<<endl;

      std::stringstream tmp;
      tmp << size;
      t= t.append(" ");
      t= t.append(tmp.str());
      cout<<"t after append file size is :"<<t<<endl;
     
      char *pch = (char*)malloc(sizeof(char) *t.length() +1);

      memset(pch,sizeof(char)*t.length()+1,'\0');

      strcpy(pch, t.c_str());

      send(sock, pch,t.size(),0);

       // calculate  number of trunks
       int count = size/2048;
       int remainder = size %2048;
     
       char * buffer ;
       //char *p;
       
       //p= buffer;

       // read in trunk and send trunk of each file until done fo each file and move on
       int result;
       if( size >= 2048)
       {
             for( int i= 0; i < count;i++)
             {
                  buffer= (char*)malloc(sizeof(char) *2048);
                  result= fread (buffer,1,2048,fp);
                  if (result != size)
                  {
                        printf(" Reading error",stderr);
                        exit(1);
                  }
                 
                  send(sock, buffer, 2048,0);
                  free(buffer);
             }
             
             //send the remainder trunk
             buffer= (char*)malloc(sizeof(char) *remainder);
             result= fread (buffer,1,remainder,fp);
             if (result != remainder)
             {
                   printf(" Reading error",stderr);
                   exit(1);
             }
             send(sock, buffer, remainder, 0);
             free(buffer);
       }
       else
       {
             buffer= (char*)malloc(sizeof(char) *size);
             memset(buffer,'\0',size);
             result= fread (buffer,1,size,fp);
             printf("number of bytes is read into buffer before sending is %d\n",result);
             if (result != size)
             {
                   printf(" Reading error",stderr);
                   exit(1);
             }
             printf("buffer is before sending : \n%s\n",buffer);
             send(sock, buffer, size, 0);
             free(buffer);
       }
       fclose(fp);
     
 
       
}


int sendFileProcess(SOCKET sock)
{

       char cwd[1024];
       list<string> myList;

       memset ( cwd, '\0',sizeof(cwd));
       
        if (getcwd(cwd, sizeof(cwd)) != NULL)
      {
           printf("Current working dir: %s\n", cwd);
        }      
      else
           perror("getcwd() error");
      /*
       //display all file names in dir and subdir
       DIR *mydir = opendir(cwd);
       struct dirent *entry = NULL;
       while((entry = readdir(mydir)))
       {
            printf("entry->d_name: %s\n", entry->d_name);
       }
       cout<<endl;
       //closedir(mydir);
        */
       
       list_all_files ( cwd, myList);// this function will get all filename in a directory
             
       sendFile(sock, myList);
 
     return 1;
}

int main(int argc, char *argv[])
{
    int sockfd, portno, n;
    struct sockaddr_in serv_addr;
    struct hostent *server;

    char buffer[256];


    portno = PORT;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
        error("ERROR opening socket");

    server = gethostbyname("ubuntu");

    if (server == NULL) {
        fprintf(stderr,"ERROR, no such host\n");
        exit(0);
    }

    bzero((char *) &serv_addr, sizeof(serv_addr));

    serv_addr.sin_family = AF_INET;

    bcopy((char *)server->h_addr,
         (char *)&serv_addr.sin_addr.s_addr,
         server->h_length);

    serv_addr.sin_port = htons(portno);
    if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
        error("ERROR connecting");

   
    sendFileProcess(sockfd);

    printf("Please enter the message: ");
    bzero(buffer,256);
    fgets(buffer,255,stdin);

    n = write(sockfd,buffer,strlen(buffer));
    if (n < 0)
         error("ERROR writing to socket");
   
    bzero(buffer,256);
    n = read(sockfd,buffer,255);
    if (n < 0)
         error("ERROR reading from socket");

    printf("client: %s\n",buffer);
    int t;
      if(( t= close(sockfd))== -1)
            printf("t is %d\n",t);
    return 0;
}

-----------

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define PORT 50000

void error(const char *msg)
{
      perror(msg);
          exit(1);
}

int main(int argc, char *argv[])
{
           int sockfd, newsockfd, portno;
           socklen_t clilen;
           char buffer[2048]="\0", buffer2[2048]="\0";
           struct sockaddr_in serv_addr, cli_addr;
      int n;
        int yes = 1;
   

      sockfd = socket(AF_INET, SOCK_STREAM, 0);
           if (sockfd < 0)
              error("ERROR opening socket");
           bzero((char *) &serv_addr, sizeof(serv_addr));
           

      portno = PORT;
      if(setsockopt( sockfd, SOL_SOCKET,SO_REUSEADDR, &yes, sizeof(int))== -1) {
            perror("setsockopt");
            exit(1);
        }

           serv_addr.sin_family = AF_INET;
           serv_addr.sin_addr.s_addr = INADDR_ANY;

           serv_addr.sin_port = htons(portno);
           
      if (bind(sockfd, (struct sockaddr *) &serv_addr,
              sizeof(serv_addr)) < 0)
              error("ERROR on binding!!!");
       
        listen(sockfd,5);
        clilen = sizeof(cli_addr);
     
      newsockfd = accept(sockfd,
                 (struct sockaddr *) &cli_addr,
                 &clilen);
           if (newsockfd < 0)
                error("ERROR on accept");
           bzero(buffer,2048);

           n = read(newsockfd,buffer,2048);
   

           if (n < 0) error("ERROR reading from socket");

           printf("Here is the message from client: %s\n",buffer);
       
        strcpy(buffer2,buffer);      
   
        //buffer contains "filename space itssize"
        // so we need to parse the buffer to get filename and its size in order to open file and write all trunks to file
       
        char seps[]= " ";
        char *token;
        char filename[300]="\0";
        char filesize[300]="\0";
       
        // establish string and get the first token
        token = strtok( buffer, seps);

        strcpy(filename,token);
        printf( "filename= %s\n",filename);

        printf( "token= %s\n",token);
        token= strtok( NULL,seps);
        strcpy( filesize, token);
        printf( "filesize= %s\n",filesize);


        FILE *fp;
        fp = fopen(buffer2, "a");// for testing purpose instead filename, just use buffer2( filename with space and its size)
        if( fp = NULL)
        {
              printf("failed to open %s to append\n",filename);
        }
        int size = atoi(filesize);
        printf("size is %d\n",size);

        // calculate  number of trunks
       int count = size/2048;
       int remainder = size %2048;
       
       // read trunks and write/append trunk of each file
       int result;
        memset(buffer,2048,'\0');
       if( size >= 2048)
       {
             for( int i= 0; i < count;i++)
             {
                  read(newsockfd,buffer,2048);
                 
                  result= fwrite (buffer,1,2048,fp);
                  if (result != 2048)
                  {
                        printf(" Writing error",stderr);
                        exit(1);
                  }
             }
             
             //remainder  of trunk
             read(newsockfd,buffer,remainder);
             result= fwrite (buffer,1,remainder,fp);
             if (result != remainder)
             {
                   printf(" Writing error",stderr);
                   exit(1);
             }
       }
       else
       {
             n =read(newsockfd,buffer,remainder);
             printf("number of byte reading into buffer at receiving is %d\n",n);
           printf("buffer is after receiving : \n%s\n",buffer);
             result= fwrite (buffer,1,remainder,fp);
             if (result != remainder)
             {
                   printf(" Writing error",stderr);
                   exit(1);
             }
       }
       fclose(fp);
     
       




           n = write(newsockfd,"Message from server",18);
           if (n < 0) error("ERROR writing to socket");

      int t1, t2;
           if( t1= close(newsockfd) ==-1)
            error("ERROR in close newsockfd");
      printf("t1 is %d\n", t1);

            if( t2= close(sockfd) == -1)
            error("ERROR in close sockfd");
      printf("t2 is %d\n", t2);
           return 0;
}


0
 

Author Comment

by:BeginToLearn
ID: 35074109
i got it !!! this one help me

(gdb) print fp
$4 = (FILE *) 0x0
hihihi
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 35080465
I thought you said that you verified that the received file was exactly the same as the sent file ?
0
 
LVL 32

Expert Comment

by:sarabande
ID: 35081358
the problem is

  if( fp = NULL)

here you do an assignment and not a comparision.

change it to

  if (fp == NULL)

Sara
0
 

Author Comment

by:BeginToLearn
ID: 35083896
Yesterday I fixed that if( fp = NULL) bug. Gdb help to on that :) due to  $4 = (FILE *) 0x0.Let me change the code to make it work for all files in directory and close this question and debug question
 regarding to

first you define char pointers buffer and p

       char * buffer ;
       char *p;
       p= buffer;

after that, both buffer and p have some random value (both the same).

later you do the malloc where buffer gets a valid pointer.

but p is still invalid and you do

  send(sock, p, remainder, 0);  

for example, what could crash if p is NULL or not pointing to valid address.

-->  I thought p and buffer point to the same address. when buffer and a value, p will automatically  get same value.
0
 
LVL 32

Expert Comment

by:sarabande
ID: 35084285
no, after char * buffer; buffer has an arbitrary value where NULL has the greatest likeliness.

with p = buffer; p points to same non-valid address (there is a very small possibility that buffer and p point to a valid address in memory by accident).

for simplicity assume p == NULL

then with buffer = (char*)malloc(...  buffer has new value which is a valid address of first element of a char array in memory. but, p still is NULL !!!!

you would need either have a

   p = buffer;

after malloc or define p as reference type (c++ only);

    char * & p = buffer;

with that p is a synonym for buffer .

Sara
0
 

Author Comment

by:BeginToLearn
ID: 35084421
i see it clearly now.tks.
0

Featured Post

Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

Join & Write a Comment

Suggested Solutions

This article shows you how to optimize memory allocations in C++ using placement new. Applicable especially to usecases dealing with creation of large number of objects. A brief on problem: Lets take example problem for simplicity: - I have a G…
There is an easy way, in .NET, to centralize the treatment of all unexpected errors. First of all, instead of launching the application directly in a Form, you need first to write a Sub called Main, in a module. Then, set the Startup Object to th…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.

757 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now