简体   繁体   中英

Reading file descriptor size from popen command for socket programming in C

I have seen similar questions asked but I seek a more specific way of how to correctly do it. I am creating a client and a server UDP FTP service where the client has options of

  • get [file_name]
  • put [file_name]
  • delete [file_name]
  • ls
  • exit

Currently, all implementations work except for my ls as I am trying to ensure the contents of "ls" are less than my buffer size so I know whether to receive/send continually. From what I have learned with research, I am getting an error because you cannot do ftell on a popen file descriptor given it is a pipe rather than the full contents of the popen command. Looking for help on how my implementation should be changed (mainly with doing ls -l on the server and sending the contents of it to the client).

My current code is as follows

FILE *fp=popen("ls -l","r");  
      fseek(fp, 0L, SEEK_END);
      long numbytes = ftell(fp);
      fseek(fp, 0L, SEEK_SET);    
      char tmp[SO_SNDBUF];
      sprintf(tmp, "%d", numbytes); 
      n = sendto(sockfd, tmp, strlen(tmp), 0, (struct sockaddr *) &clientaddr, clientlen); //send ls file size
      if (n < 0) 
        error("ERROR in sendto");  
      if(numbytes<SO_SNDBUF)
      {
        bzero(buf, SO_SNDBUF);
        fread(buf, sizeof(char), numbytes, fp);
        n = sendto(sockfd, buf, numbytes, 0, (struct sockaddr *) &clientaddr, clientlen);
        if (n < 0) 
          error("ERROR in sendto");
      }
      else
      {
        //outgoing file is larger than buffer size
        long totalSent = 0;
        while(totalSent<numbytes)
        {
          bzero(buf, SO_SNDBUF);
          if((numbytes-totalSent)<SO_SNDBUF)
          {
            fread(buf, sizeof(char), numbytes-totalSent, fp);
            n = sendto(sockfd, buf, numbytes-totalSent, 0, (struct sockaddr *) &clientaddr, clientlen); //send ls contents
            if (n < 0) 
              error("ERROR in sendto");
          }
          else
          {
            fread(buf, sizeof(char), SO_SNDBUF, fp);
            n = sendto(sockfd, buf, SO_SNDBUF, 0, (struct sockaddr *) &clientaddr, clientlen); //send ls contents
            if (n < 0) 
              error("ERROR in sendto");
          }
          totalSent+=n;
        }
      }
      pclose(fp);   

The main portion of code that would need modifying is: To correctly get how many bytes ls -l is returning

FILE *fp=popen("ls -l","r");  
      fseek(fp, 0L, SEEK_END);
      long numbytes = ftell(fp);
      fseek(fp, 0L, SEEK_SET);    
      char tmp[SO_SNDBUF];
      sprintf(tmp, "%d", numbytes); 

How about:

system("ls -l > ls.txt");
FILE *fp = fopen("ls.txt", "r");
//...

If it is not too much to create a temporary file. The advantage is, that you have your content ready (mainly the size).

The other solution would be (as suggested) to read from popen line by line into an array of strings and calculating the total amount of bytes while doing so. The disadvantage here is memory allocation (but we read it into memory anyway).

Since you are going to read it all in anyway, you could simply do this, if you are on a platform where getdelim exists, which you probably are if you are using ls command:

FILE *fp = popen("ls -l","r");
char *buf = NULL;
size_t buf_size = 0;
ssize_t result = getdelim(&buf, &buf_size, EOF, fp);
if (result < 0) {
    perror("reading output of popen ls");
    // any other error handling
} else {
    // result contains size of entire ls output
    // buf contains the actual data
    // buf_size is useful only, if you want to re-use buf
}
free(buf); // if buf is NULL, does nothing

A note about using getdelim to get the entire file: If reading an actual file from disk, it may be too large to fit in memory. But here we are reading output of ls command, which for any practical purposes can't be that large.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM