dir_socket

Hi,

I am trying to send many images from the same folder via socket.
Even though this code runs, there are semantic errors, in fact, the following message shows:

error: while sending image


and no bytes are in fact sent.

Another way was suggested in my previous post, which discussed the option of writing algorithm as a function, and then repeat that function for every file, but like I said, I cannot do it that way. I need to use a 'send' command only once, and send 'all' the pics in the folder.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
const char *dir = "/home/Desktop/pics";

    if (chdir(dir) == -1) {
        perror(dir);
        return 1;
    }

    DIR *dirp = opendir(".");

    for (struct dirent *dent; (dent = readdir(dirp)) != NULL; )
    {
        const char *nm = dent->d_name;

        if (strcmp(nm, ".") == 0 || strcmp(nm, "..") == 0)
            continue;

        struct stat file_stats;
        if (stat(nm, &file_stats) == -1)
            perror(nm);

        else
            printf("%9u: %s\n", (unsigned)file_stats.st_size, nm);


long conv_num = htonl((unsigned)file_stats.st_size);


send(new_socket, &conv_num, sizeof(conv_num), 0);


char outfile[1000];
sprintf(outfile, "../copydir/%s", nm);

// Copy the file in BUFSIZ chunks.
char buf[40];
FILE *fin = fopen(nm, "rb");
FILE *fout = fopen(outfile, "wb");
size_t cnt;
size_t sent{};
while ((cnt = fread(buf, 1, sizeof buf, fin)) != 0){
    int nbytes = send(new_socket, fin, sizeof(fin) , 0);
    if (nbytes <= 0) {
        std::clog << "error: while sending image\n";
        break;
    
   sent += nbytes;
    cout<<nbytes<<"================"<<endl;}
            fclose(fout);
            fclose(fin);
        }

}
closedir(dirp);
Last edited on
I need to use a 'send' command only once
Actually, then you cannot use send(...) in a loop. You need to build a dynamic buffer [std::vector] that contains all the data before you call the send(...) function.

Sending fin doesn't make too much sense:
int nbytes = send(new_socket, fin, sizeof(fin) , 0);
?

However when there are no bytes send it is strange. A negative number denotes an error. However you should check the error [errno] to see what went wrong.
I changed line 41 to this:
int nbytes = send(new_socket, fout, sizeof(fout) , 0);

No negative number was returned. Only the message in line 43 shows, implying that the bytes are 0.

But I am now not sure what to do, to send the image.
Can I send the images without building the vectors?

I changed line 41 to this:
That makes no sense either. You send a pointer to an internal structure. How do you come to such an idea to send that?

Can I send the images without building the vectors?
Sure you can find out the size of the file using fseek:

http://www.cplusplus.com/reference/cstdio/fseek/

You need to creat a buffer large enough to hold the data and read the file data to it.

Once again: In the loop you read from the file only. Do not call send(...).

Only the message in line 43 shows, implying that the bytes are 0.
Then I would think something on the receiver side is wrong.
I already know the size of the files since line 22 prints them.
And now that I know the sizes, let me ask again:

How do I send the pictures without vectors?

Can you lead me to an example where they do that?
I couldn't find anything anywhere.
Do you really absolutely positively have to call send() only one time to send the entire directory full of photos? That's a pretty strange requirement.

If you really do need to send in one call then:

I already know the size of the files since line 22 prints them.


You know the size of one file. You will also need to keep track of the total size of all the files. Rather that growing a vector that could reach into the gigabytes, you could copy all the data to send for the source files into a single output file. Then get the size of the output file, allocate a buffer for it, read it into the buffer and finally send the buffer.

I changed line 41 to this:
Read the man page for send() again. You need to pass it the address of a memory buffer that contains the actual bytes to send, not the address if a stream.

@dhayden,

Do you really absolutely positively have to call send() only one time to send the entire directory full of photos?

I will eventually have to implement this code into a network camera that takes pictures and sends them continuously to the client, and it is 'one' send for all pics. Since I don't have this tool at home, I am working with a folder.




You know the size of one file. You will also need to keep track of the total size of all the files

line 22 prints all files names and their sizes, why are you saying that it prints one ?

you could copy all the data to send for the source files into a single output file

ok, but how?


I am feeling a bit confused about your description,
all I need to see is an example where they do that, so I can see the logic.
Maybe you can provide a sample that I can look at ?

I will eventually have to implement this code into a network camera that takes pictures and sends them continuously to the client, and it is 'one' send for all pics. Since I don't have this tool at home, I am working with a folder.


I doubt this. I worked on a project a few years ago that streamed images from a camera, and we sent each successive image separately. I suspect you really want to do repeated sends of multiple images rather than a single send.
we sent each successive image separately
I suspect you really want to do repeated sends of multiple images rather than a single send.


That's exactly what I mean. I want to use a single 'send' command that sends all the pics to the client.

Now, how do i do that if I take pics from a folder?
That's exactly what I mean. I want to use a single 'send' command that sends all the pics to the client.
So to be clear, you want the user to use a single "send" command? Up to now, we've been talking about the send() function from the socket library and your need to use a single call to that function.
I will eventually have to implement this code into a network camera that takes pictures and sends them continuously to the client, and it is 'one' send for all pics.


Are you talking about streaming video or streaming images? If you are talking about streaming images (like MJPEG), the camera will send each captured image separately. So, each image will have it's own send command.

We worked with streaming video a little bit, but we had a 3rd party tool to do it for us. Look into gstreamer--it might give you the support you want. We ended up scrapping the streamed video and just went with MJPEG because it was simpler and gave us what we wanted.

So, "sends them continuously" does not require "'one' send for all pics".


Last edited on
streaming images, and I need 'one' send command inside a loop

@dhayden
I meant the 'send' command.
Sorry if I haven't been to clear about it.
Last edited on
I need to use a 'send' command only once, and send 'all' the pics in the folder.
and I need 'one' send command inside a loop


Do you see the confusion you are causing us? You spend most of the thread telling us that you need to do this by calling send one time. Now you say you want to call it inside a loop. That means multiple calls to the send command.

I don't really know what you are asking.

For what it's worth, I would do the following:

1
2
3
4
5
6
For each file in directory:
     read file
     while data remains to be sent
         send data
    end while
end for


When you get to the camera it will become:

1
2
3
4
5
6
While active:
     capture image data
     while data remains to be sent
         send data
    end while
end wile


I am sorry, but sometimes is hard to figure out what to do without the necessary equipment, let alone explain it.
Now I would need you to be more specific.
Referring to your first code block:

I have already taken care of line 1 and 2, now the question is, how to get the data to send?
So far I obtained the file names and their size.
What is this 'one send' all about?

Do you want the function call send() to appear exactly once in your source code?
That's easy to do.

Do you want to call send() exactly once at run-time, and expect it to fully complete the transfer of many megabytes of data read from all your files?
You're screwed. send() makes no such guarantee that it will complete the sending of an arbitrarily large amount of data in a single call.

Besides, if your ultimate goal is to stream images from somewhere, you can't know in advance how much data you have, so a single run-time call just isn't going to happen.

Just let go of that security blanket and listen to what the 100's of years of programming experience of the resident members paying attention to this thread are telling you.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>

// send them bytes!
ssize_t sendBytes(int sockfd, const void *buf, size_t len) {
  const char *p = buf;
  size_t sent = 0;
  ssize_t result;
  do {
    result = send(sockfd,&p[sent],len,0);
    if ( result > 0 ) {
      // deal with whatever partial success we have
      sent += result;
      len -= result;
    } else {
      // something wrong
      break;
    }
  } while ( len > 0 );
  return result;
}

// sends an integer in network byte order
ssize_t sendInt(int sockfd, int value) {
  long n = htonl(value);
  return sendBytes(sockfd,&n,sizeof(n));
}

// sends a string, prefixed with it's length
ssize_t sendString(int sockfd, const char *str) {
  size_t len = strlen(str);
  ssize_t result = (sockfd,len);
  if ( result <= 0 ) return result;
  result = sendBytes(sockfd,str,len);
  return result;
}

// send exactly one image, along with the necessary image length
ssize_t sendImage(int sockfd, const char *filename, size_t filelen) {
  ssize_t result;

  FILE *fin = fopen(filename, "rb");
  if ( fin ) {
    // Send the file length
    result = sendInt(sockfd,filelen);
    if ( result <= 0 ) { fclose(fin) ; return result; }

    char buff[BUFSIZ];
    size_t cnt;
    while ((cnt = fread(buff, 1, sizeof buff, fin)) != 0) {
      result = sendBytes(sockfd,buff,cnt);
      if ( result <= 0 ) break;
    }
    fclose(fin);
  }
  return result;
}

// Send all the images in a directory
ssize_t sendDir(int sockfd, const char *dirname) {
  DIR *dirp = opendir(".");
  ssize_t result = 0;
  for (struct dirent *dent; (dent = readdir(dirp)) != NULL; )  {
    const char *filename = dent->d_name;

    // check for self and parent directories
    if (strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0)
      continue;

    // other checks, like it's not a sub-directory or not an image?

    struct stat file_stats;
    if (stat(filename, &file_stats) == -1) {
      perror(filename);
      break;
    }
    result = sendImage(sockfd,filename,file_stats.st_size);
    if ( result <= 0 ) break;
  }
  closedir(dirp);
  return result;
}

int main ()
{
  int sockfd = 0;
  // add your open connection code here.
  sendDir(sockfd,"/home/Desktop/pics");
}


If you want to send a file (a common thing for proxies and webservers to do), there's a sendfile() function that'll do for you.
http://man7.org/linux/man-pages/man2/sendfile.2.html
@salem

There's an error in your first function.
I'm not sure how to fix it.

In function ‘ssize_t sendBytes(int, const void*, size_t)’:
server_4.cpp:23:19: error: invalid conversion from ‘const void*’ to ‘const char*’ [-fpermissive]
   const char *p = buf;

 
const char *p = buf;

should be:
 
const void *p = buf;
Did it work?
Topic archived. No new replies allowed.