Solved

receiving

Posted on 2011-03-17
36
391 Views
Last Modified: 2012-05-11
hi all,
 I want to send all files inside a directory from client to server. Here is my approach:
      client:
           + send total number of files from client to server
           + repeat a for loop to send each file and its size and content
      server:
           + receive total number of files and set condition for number of iteration in for loop
           +  repeat for loop to receive each file and content

 It works for the first file. When it repeat for second file, server get segmentation fault. I see there is a mismatch between send and receive buffer. However, i can't find out my logic error. Please help.

------------------------------------------
 
#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(1);
}

int GetTotalFile (SOCKET sock)
{
        char buffer[2048]="\0";
        int n;
      n = read(sock,buffer,2048);

           if (n < 0) error("ERROR reading from socket");
           printf("Here is the message from client (TotalFile): %s\n",buffer);
        int size = atoi(buffer);

        return size;
}

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);

        int totalfile  = GetTotalFile(newsockfd);
        printf("total files need to receive are %d\n",totalfile);

        for( int i = 0; i <totalfile;i++)
        {      

                 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);

              int size = atoi(filesize);
              printf("size is %d\n",size);

       

              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);
              }
       
                     // 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
                         if( remainder != 0)
                         {                           
                        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("remainder is %d\n",remainder);
                       printf("buffer is after receiving : \n%s\n",buffer);
                         result= fwrite (buffer,1,remainder,fp);
                         printf("result is %d\n",result);
                         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;
}
--------------------------------------

#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)) {

       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;
       if( strcmp(pEntry->d_name,".") != 0 && strcmp(pEntry->d_name,"..") != 0)
            sFound = sStartDir + string ( "/") + string ( pEntry->d_name);
       
       if( sFound.length() != 0)
           lstFound.push_back ( sFound);
   }
}
 /*
       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;

       }*/

void sendFile ( SOCKET sock,  list<string>& myList)
{
       cout<<" in sendFile myList size: "<<myList.size()<<endl;
 
       //string  totalfile;
        std::stringstream totalfile;
                totalfile << myList.size();
       string a = totalfile.str();
       


        char *tf = (char*)malloc(sizeof(char) *a.length() +1);

        memset(tf,sizeof(char)*a.length()+1,'\0');

        strcpy(tf,a.c_str());

        send(sock, tf,a.size(),0);



         
   
       //printf("in decimal, totalfile is : %s\n",tp);
   
       //send(sock, pch,t.size(),0);
     
       list<string>::iterator ptr;
       
       string t;
       FILE *fp;
       for ( ptr =myList.begin(); ptr !=myList.end(); ptr++)
       {
              t = *ptr;
             // cout<<"<LIST> has :"<<t<<endl;
       }  


       for( ptr =myList.begin(); ptr !=myList.end(); ptr++)
       {  
              t = *ptr;
              cout<<"t is :"<<t<<endl;
             
              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);
     
              // add a " " then its filesize to filename then send it to server side
              // so server side can apply same formula while dealing with trunks.
             
              std::stringstream tmp;
              tmp << size;
              t= t.append(" ");
              t= t.append(tmp.str());
              cout<<"t after append its filesize 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 ;

              // read in trunk and send trunk of each file until done fo each file and move on
              int result = -1, byte_sent = -1;  
              //if filesize is larger or equal 2048
              if( size >= 2048)
              {
                  for( int i= 0; i < count;i++)
                  {
                      printf("In 2048 block\n");
                      byte_sent= -1 ;
                      buffer= (char*)malloc(sizeof(char) *2048);
                      memset(buffer,'\0',2048);
                      result= fread (buffer,1,2048,fp);
                 
                      if (result != 2048)
                      {
                          printf(" Reading error in block 2048\n",stderr);
                          exit(1);
                      }
                     byte_sent= send(sock, buffer, 2048,0);
                   
                     if( byte_sent < 2048)
                     {
                        printf("Fail to send whole 2048 block \n",stderr);
                     }
                   
                     free(buffer);
                     // NO need to seek to next block because fread will implicitly take care of it.
                     printf("i is %d. next block \n",i);
                  }//end inner for
                  //read the last block as remainder
                  if( remainder != 0)
                  {
                        printf("In remainder block\n");  
                        //send the remainder trunk
                        buffer= (char*)malloc(sizeof(char) *remainder);
                      memset(buffer,'\0',remainder);
                        result= fread (buffer,1,remainder,fp);
                        if (result != remainder)
                        {
                             printf(" Reading error in remainder ",stderr);
                             exit(1);
                        }
                        byte_sent = send(sock, buffer, remainder, 0);
                 
                        if( byte_sent < remainder)
                        {
                            printf("Fail to send remainder block  \n",stderr);
                        }
                        free(buffer);
                  }
             //if filesize is smaller 2048
             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);
             
                byte_sent= send(sock, buffer, size, 0);
             
                 if( byte_sent < size)
                 {
                      printf("Fail to send whole block smaller than 2048 \n",stderr);
                 }

                 free(buffer);
             }//end else
             fclose(fp);
       }
    }//end of outer for
         
}//end of function
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;
}


0
Comment
Question by:BeginToLearn
  • 18
  • 14
  • 4
36 Comments
 
LVL 32

Accepted Solution

by:
phoffric earned 300 total points
ID: 35160495
>> When it repeat for second file, server get segmentation fault.

Definitely some memory corruption here. You have ordering incorrect in some of your memset. (Some others are ok.)

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

>> memset(tf,sizeof(char)*a.length()+1,'\0');

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

See  http://www.cplusplus.com/reference/clibrary/cstring/memset/
0
 

Author Comment

by:BeginToLearn
ID: 35160620
can you also point out other errors?tks.
0
 
LVL 32

Expert Comment

by:phoffric
ID: 35160682
Are you still getting a seg fault even after fixing this problem? All I was looking for was some memory corruption given your statement.

If you still are having problems, then the easiest way to identify the problem is to run to GUI debuggers (for client and server) and step through them in a logical manner.

There is also Valgrind, which should catch memory corruption issues (or so I've told).
     http://valgrind.org/

Sorry, I haven't used this one; I used Insure++ from Parasoft to catch these type of problem while running a program.
0
 

Author Comment

by:BeginToLearn
ID: 35160837
I am offline for 5 hrs.i gonna try
0
 

Author Comment

by:BeginToLearn
ID: 35160858
When I ran debugger,for second time,i saw mismatch between send n receive
0
 
LVL 32

Expert Comment

by:phoffric
ID: 35160878
>> i saw mismatch between send n receive
But no segment fault?
0
 

Author Comment

by:BeginToLearn
ID: 35161068
Then segmentation faut due to strtok
0
 

Author Comment

by:BeginToLearn
ID: 35161148
I mean strtok.it parse file name and its size only
0
 
LVL 32

Expert Comment

by:phoffric
ID: 35161275
I ran your code in Cygwin and got no seg faults. Show the LOC where you get seg fault.

>> fp = fopen(buffer2, "a")
Is it intention that you create a file using:
    filename filesize
as the new filename?

>> I mean strtok.it parse file name and its size only
Sorry, I didn't follow you. But I'll be back tomorrow to see any progress.

If you haven't done so already, I suggest that you download ddd using Cywin's setup, and also Xming. (You want to avoid CygwinX.)
0
 
LVL 32

Expert Comment

by:phoffric
ID: 35161302
If you could state in words what your sequence of messaqing requirements are, that may be useful. Also, what is the technique you are trying to use to cause the client and server to exit?

0
 

Author Comment

by:BeginToLearn
ID: 35161483
First of all,i must review the fopen(buffer2,“a").you are right.i intetionally open new file.
secondly,client send number of files in directory to server.then it send each filename ands its size to server and send trunk of each file until done.sever get total file and use it for iteration for loop.then it parse file name and its size to know how many times it repeat  for loop toreceive trunk file.
0
 

Author Comment

by:BeginToLearn
ID: 35162469
For testing purpose, I create filename with its size in order to verify code. So it's ok . Here is the debug value that I see unexpect result.

Client :
  t after append its filesize is :/home/ubuntu/program/help/text_compare_replacements.html 3947
In 2048 block
i is 0. next block
In remainder block

Server:
   Here is the message from client: /home/ubuntu/program/help/text_compare_replacements.html 3947¿<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<!-- saved from url=(0029)http://www.helpandmanual.com/ -->
<head>
   <title>Text Compare Replacements</title>
   <meta name="generator" content="Help &amp; Manual" />


I can see a messup in server side !!!

0
 

Author Comment

by:BeginToLearn
ID: 35162831
after I delete some files in directory in order to debug easier, I can see a weird thing:
 Client : t after append its filesize is :/home/ubuntu/program/server.c 5821
 Server: ere is the message from client: /home/ubuntu/program/server.c 5821XX_3.4

how can it has those extra xx_3.4?
BTW, i add some memset() before each time to read info into buffer to eliminate any left over from previous operation.
0
 

Author Comment

by:BeginToLearn
ID: 35163064
Another wierd:


Here is what i want:
  Client : send filename + its size                   Server : receive filename + its size
  Client : send trunk of each file                      Server: receive trunk of each file

 It execute like that for the first to files :)
  Then moving to third file:
   Client : send filename + its size                   Server : receive filename + its size
                                                                                 receive trunk of each file

    Client : send trunk of each file

So I got Segmentation fault as result hix hix. Please advise !!!!!!!!!!!!!!!!!!

Below is the copy from ternimal

server
---------------------
Here is the message from client (TotalFile): 7
total files need to receive are 7
Here is the message from client: /home/ubuntu/program/client 25966
File name and its size just received!!!. No content here
filename= /home/ubuntu/program/client
token= /home/ubuntu/program/client
filesize= 25966
size is 25966
start receiving file content , respective to filename
In 2048 block
i is 0. next block
In 2048 block
i is 1. next block
In 2048 block
i is 2. next block
In 2048 block
i is 3. next block
In 2048 block
i is 4. next block
In 2048 block
i is 5. next block
In 2048 block
i is 6. next block
In 2048 block
i is 7. next block
In 2048 block
i is 8. next block
In 2048 block
i is 9. next block
In 2048 block
i is 10. next block
In 2048 block
i is 11. next block
In remainder block
Here is the message from client: /home/ubuntu/program/server.c 5972XX_3.4
File name and its size just received!!!. No content here
filename= /home/ubuntu/program/server.c
token= /home/ubuntu/program/server.c
filesize= 5972XX_3.4
size is 5972
start receiving file content , respective to filename
In 2048 block
i is 0. next block
In 2048 block
i is 1. next block
In remainder block
Here is the message from client: /home/ubuntu/program/client.c 9288
#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)) {

       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;
       if( strcmp(pEntry->d_name,".") != 0 && strcmp(pEntry->d_name,"..") != 0)
            sFound = sStartDir + string ( "/") + string ( pEntry->d_name);
       
       if( sFound.length() != 0)
           lstFound.push_back ( sFound);
   }
}
 /*
       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;

       }*/

void sendFile ( SOCKET sock,  list<string>& myList)
{
       cout<<" in sendFile myList size: "<<myList.size()<<endl;
 
       //string  totalfile;
        std::stringstream totalfile;
                totalfile << myList.size();
       string a = totalfile.str();
       


        char *tf = (char*)malloc(sizeof(char) *a.length() +1);

        memset(tf,sizeof(char)*a.length()+1,'\0');

        strcpy(tf,a.c_str());

        send(sock, tf,a.size(),0);
5972XX_3.4
File name and its size just received!!!. No content here
filename= 5972XX_3.4
token= 5972XX_3.4
Segmentation fault
ubuntu@ubuntu:~/program$


client
--------------------
Current working dir: /home/ubuntu/program
 in sendFile myList size: 7
t is :/home/ubuntu/program/client
t after append its filesize is :/home/ubuntu/program/client 25966
File name and its size just sent!!!. No content here
just send file name and its size !!!!!
start sending file content , respective to filename
In 2048 block
i is 0. next block
In 2048 block
i is 1. next block
In 2048 block
i is 2. next block
In 2048 block
i is 3. next block
In 2048 block
i is 4. next block
In 2048 block
i is 5. next block
In 2048 block
i is 6. next block
In 2048 block
i is 7. next block
In 2048 block
i is 8. next block
In 2048 block
i is 9. next block
In 2048 block
i is 10. next block
In 2048 block
i is 11. next block
In remainder block
t is :/home/ubuntu/program/server.c
t after append its filesize is :/home/ubuntu/program/server.c 5972
File name and its size just sent!!!. No content here
just send file name and its size !!!!!
start sending file content , respective to filename
In 2048 block
i is 0. next block
In 2048 block
i is 1. next block
In remainder block
t is :/home/ubuntu/program/client.c
t after append its filesize is :/home/ubuntu/program/client.c 9288
File name and its size just sent!!!. No content here
just send file name and its size !!!!!
start sending file content , respective to filename
In 2048 block
i is 0. next block
In 2048 block
i is 1. next block
In 2048 block
i is 2. next block
In 2048 block
i is 3. next block
In remainder block
t is :/home/ubuntu/program/test
t after append its filesize is :/home/ubuntu/program/test 8712
File name and its size just sent!!!. No content here
just send file name and its size !!!!!
start sending file content , respective to filename
In 2048 block
i is 0. next block
In 2048 block
i is 1. next block
In 2048 block
i is 2. next block
In 2048 block
i is 3. next block
Fail to send whole 2048 block
In remainder block
ubuntu@ubuntu:~/program$

client.c
server.c
0
 
LVL 32

Assisted Solution

by:sarabande
sarabande earned 200 total points
ID: 35163909
to avoid those extra 'xx_3.4' thing you either need to add a binary zero character to the buffer you send or you do that on the receiver side.

if a buffer containing text has no zero termination, an output function would go on in memory until it finds a zero char by accident. so the 'xx_3.4' are only garbage from your current memory.

Sara
0
 
LVL 32

Expert Comment

by:phoffric
ID: 35164071
You still have some memset wrong in your two latest client.c and server.c files in http:#35163064. For example:
   
memset(buffer,2048,'\0');

Open in new window

Please check every memset in both files so that you do not clobber memory.

In GetTotalFile you have:
        char buffer[2048]="\0";
        int n;
        n = read(sock,buffer,2048);

        if (n < 0) error("ERROR reading from socket");
        printf("Here is the message from client (TotalFile): %s\n",buffer);

Open in new window

If n is 2048, then you did not leave room for the terminating null byte in your debug printf.
So, make the buffer size 2048+1. (This error could potentially cause a segment fault since the %s in the printf will cause printing to be done until a null byte is found, and that could end up with an unmapped virtual address.)

You client is C++, so suggest that you change extension from .c to .cpp
I don't know why you have C++ headers in your server, since I didn't see any usage of them in a quick look. If so, you can remove these headers and keep the .c extension. I don't think you remembered to add the -Wall option. If you did, you probably would pick up items like:
printf(" Writing error",stderr);

Open in new window

Here's a case where the debug statements actually can contribute to your seg fault problem. To compile in Cygwin a .c file, you should use:
     gcc -Wall  -std=c99 client.c -o client

I recommend that you add functions to your server to match corresponding message sends from the client. Not sure why you don't emulate ftp by just having the client send one file at a time without the entire list ahead of time. The code would look a little cleaner, and by having smaller functions, you can test each function separately. Distinguish the functions between file-io and message transfer. Likewise, you should break out in your client file-io operations vs message transfer operations.


Tip on posting: When making large copy and paste posts, use the code button.
0
 
LVL 32

Expert Comment

by:sarabande
ID: 35164169
the sendFile function is far too long-winded and error-prone. you must simplify it.

also your messages sent needs to get some structure so that the receiving side knows what it receives.

each message should begin with length of the message and a message id. then the message data would be added.

so first message is the notification of how much files would be transfered. nothing else. the send buffer then would look like

   [12] [1] 1234

where 12 is the total length of the message, 1 is the message id, and 1234 is the number of files.

i did the length into [] cause you would transfer it as 32-bit integer, same as the message id. that way the receiver can read 4 bytes for getting length and 4 more bytes for id and must not operate on variable length string numbers. it also simplifies the length calculation where you otherwise would have to consider the number of digits of the total length and id number as well.

if doing so, your sendFile function would begin with

void sendFile ( SOCKET sock,  list<string>& myList)
{
    cout<<" in sendFile myList size: "<<myList.size()<<endl;

    char buffer_in[2048] = { 0 };

    char buffer_out[2048] = { 0 };

    //string  totalfile;
    std::stringstream message1;
    message1 << myList.size();

    unsigned int buflen = 0;

    MessageHeader mh;
    mh.mlen = sizeof(MessageHeader) + message1.length() + 1;
    mh.mid  = 1;   // message id for initial message

    // note if sender and receiver (may) have different endianess you need to 
    // translate the two integers from host to network order calling htonl
    // on the receiver side you would do the reverse by calling ntohl

    // copy header to output buffer
    memcpy(&buffer_out[buflen], &mh, sizeof(mh));
    buflen += sizeof(mh);

    // note the strcpy would copy a zero terminator at end
    strcpy(&buffer_out[buflen], message1.str().c_str());
    buflen += message1.str().length() + 1;


    send(sock, buffer_out, buflen, 0);

Open in new window


did you get the idea?

Sara
0
 
LVL 32

Expert Comment

by:sarabande
ID: 35164195
if forgot to post the structure MessageHeader which simply is

struct MessageHeader
{
    unsigned int mlen;
    unsigned int mid;
};

note, i assumed 32-bit integers on your systems. if that could not be granted you should use explicit sized integer type like uint32_t (or similar depending on compiler).


Sara
0
Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

 

Author Comment

by:BeginToLearn
ID: 35165883
Let me read those comments carefully
0
 
LVL 32

Expert Comment

by:phoffric
ID: 35165954
I assume that you were only sending text files that have no embedded null bytes in them, right? Otherwise, as Sara mentioned, your debug statements that have %s of a buffer will result in a truncated debug output; but no harm done in terms of writing to the disk. I recommend using ddd debugger rather than filling up with debug statements (which you then have to debug!).

You should modularize your program so that you have a function whose sole responsibilty is to send one file, and have its counterpart in the server. This rewrite, if you choose to take on this mission should be in another question to keep redesign rewrites out of this question in order to keep this question focussed on your seg fault issue.



I see that you use bzero and also memset to zero out a buffer. Why not just use bzero and eliminate the ordering issue.

A malloc followed by a zeroing out of the allocated area can be replaced by a calloc.
     http://www.cplusplus.com/reference/clibrary/cstdlib/calloc/
But, since you are doing C++ there, why not just use new and delete?
         buffer= (char*)malloc(sizeof(char) *2048);
Since you know the max malloc'd size will be, why not avoid dynamic allocation and just use a buffer on the stack (or elsewhere).
0
 

Author Comment

by:BeginToLearn
ID: 35166153
Let me install ddd debugger on ubuntu first. My assumption is directory can have any file type. I use dynamic allocation because i want to save memory to avoid crash. Can you give specific " use a buffer on the stack (or elsewhere)" and what need to break down in modules to make avoid error-prone? Then I can reorganize the code. Then I can open a new question and close this question because it's too long.

0
 
LVL 32

Expert Comment

by:phoffric
ID: 35166360
You could just define
#define BUFFER_SEND 2048
#define BUFFER_LEN (BUFFER_SEND + 1)
char buffer[ BUFFER_LEN ];

Open in new window

and just use buffer (or additional buffers if desired for extra readability).
For simplicity, in client, you could just make your buffers global (i.e., outside of functions)

Don't forget the -Wall - there are some useful points being made.

On each side..
One function for transfer of number of files in your list. (Although I did mention that you don't have to do it that way - you could just send one "filename   filesize" string followed by the body of the file.
One function to send "filename   filesize" string
One function to send the body of the file

Comment:
I don't think you need to deal with whether a file is greater than BUFFER_SEND. While I don't believe that is the cause of your seg fault, it does clutter up your design. Before you receive the first chunk of data from the file, you know how many bytes you will receive. So that is your count. The server just keeps reading bytes

When you read n bytes, you should check the return value always checking for errors of course; but also to determine how many bytes you actually read. It is not necessarily an error if you read less than n bytes - it just means that you need another pass on read. In any case you just decrement the byte_count_remaining variable that was initialized to the original file size, and you know that you are done when this  byte_count_remaining variable is 0. If somehow you end up with more or less than this final value of 0, then you have an error.
0
 
LVL 32

Expert Comment

by:phoffric
ID: 35166397
BTW - after fixing up the memset's and ran your program with one folder, it successfully transferred the 4 files in the folder - same file size and diff of 0. But it immediately crashes on a strcpy when you try to move to the parent folder.
0
 

Author Comment

by:BeginToLearn
ID: 35166430
haiz a lot of bugs !!!
0
 
LVL 32

Expert Comment

by:phoffric
ID: 35166490
Oh, one tip when using ddd. Create wrapper functions SEND and READ so that you don't have to find all the places to add breakpoints. This way just one breakpoint in the SEND and one in the READ will help with the breakpoint management.

You can keep your stack window open after selecting Status -> Backtrace.... Then you can hit the caller of SEND or READ and find out which one is a problem.

0
 
LVL 32

Expert Comment

by:phoffric
ID: 35166498
>> haiz a lot of bugs !!!
Do you need help with the warnings?
0
 

Author Comment

by:BeginToLearn
ID: 35166617
I am changing all define about BUFFER_SEND, BUFFER_LEN now. Then I need to modify my code base on Sara and your suggestions and run ddd. Oh i forgot, I can't use Cygwin. I must use Ubuntu so "wall" cant apply here.This is my first time to use ubuntu and debugger.
0
 

Author Comment

by:BeginToLearn
ID: 35166646
>>Do you need help with the warnings?
Let my try first
0
 
LVL 32

Expert Comment

by:phoffric
ID: 35167068
>> I must use Ubuntu so "wall" cant apply here.
Not sure what you mean. The -Wall option is part of gcc and g++. For example:
     g++ -ggdb -Wall client.c -o client

0
 

Author Comment

by:BeginToLearn
ID: 35167076
After I change BUFFER_SEND, BUFFER_LEN and memset() regarding to the size and argument order in both client and server,there is a good news. No more truncated. BTW, i don't know why I could make wrong argument order :)

Let me study Sara suggestion now hihi.
0
 
LVL 32

Expert Comment

by:sarabande
ID: 35167137
i once had written

   message1.length()

where it should have been

  message1.str().length()

Sara
0
 

Author Comment

by:BeginToLearn
ID: 35167253
 sendFile will send the message which consist of  total length of the message, message id, the number of files. In comparison to my code which send only number of files. We need to send addition info: total length of message and message id.

 Could you please explain why we need to send total length of message and message id?  
 
0
 
LVL 32

Expert Comment

by:phoffric
ID: 35167288
You realize that you already are sending a message header of sorts; namely, you send
1) the total number of files to receive
2) for each file you send a pseudo message header
    a) filename
    b) filesize (i.e., the length of the remaining part of the message)

Why do you have the client say
        printf("Please enter the message: ");
        n = write(sockfd,buffer,strlen(buffer));

Where is the server reading this user entered message?
0
 

Author Comment

by:BeginToLearn
ID: 35167349
Why do you have the client say
        printf("Please enter the message: ");
        n = write(sockfd,buffer,strlen(buffer));

--> this is just the old testing when I set up connection between client & server. Let me comment it out.

You realize that you already are sending a message header of sorts; namely, you send
1) the total number of files to receive
2) for each file you send a pseudo message header
    a) filename
    b) filesize (i.e., the length of the remaining part of the message)

Could you please explain  why we need to send total length of message and message id? I really want to understand the differences and their purposes before I make a change regarding to message header.
Tks a lot for your patient.  
0
 
LVL 32

Expert Comment

by:phoffric
ID: 35167438
The message id is useful for some applications to enforce synchronization and verfication. It probably isn't necessary in your p2p application since you are using tcp. Every designer has a different opinion.

The definition of Length is up to you. My recommendation is that it should be the same value as you are currently sending; namely, the length of the file that you are transmitting.

In a number of large projects, the message length attribute in the message header was not defined clearly enough causing large debugging costs. In some cases it meant the number of bytes in the entire message; in others it meant just the number of bytes in the body of the message that follows the message header. I prefer the latter definition, as it then allows you to modify the message header structure without having to change the value of the Length.
0
 

Author Comment

by:BeginToLearn
ID: 35167529
Ic. let me close this question now. And create a new question regarding to mismatch. tks .
0

Featured Post

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

Join & Write a Comment

This tutorial is posted by Aaron Wojnowski, administrator at SDKExpert.net.  To view more iPhone tutorials, visit www.sdkexpert.net. This is a very simple tutorial on finding the user's current location easily. In this tutorial, you will learn ho…
This is a short and sweet, but (hopefully) to the point article. There seems to be some fundamental misunderstanding about the function prototype for the "main" function in C and C++, more specifically what type this function should return. I see so…
The goal of this video is to provide viewers with basic examples to understand how to create, access, and change arrays in the C programming language.
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

705 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

21 Experts available now in Live!

Get 1:1 Help Now