-3

I'm building the communication module of an application on c++, I'm using windows socket to make the connection and the send() function to send files. When I try to send an image, it comes broken in the server client, but when I send a Text File, it works normally.

My application is divided into Client and Server. My Client connects to the Server and stores a png file into a string variable (data). Out of 512 out of 512 bites, the program stores the array that contains the image into "data", and send it via socket::

//Stores the binary
int imgBinaryExtractor(){   
    int i = 0;
    
    
    std::ifstream file1;
    char ch; //Used to storde the image characters into img_binary
    const char* sfile = "original.png";

    file1.open(sfile, std::ios::binary);


while (file1.get(ch)) {

    
    img_binary[i] = ch; //Put the png data into the array
    file_size++; //Stores the size of the image
    i++; //Just a controller
    //std::cout << "\nCaractere atual no char: " << ch;
    //std::cout << "\nCaractere atual no aray: " << img_binary[i];
}

    file1.close();
    std::cout << "file_size: " << file_size << std::endl;

    int a = 512;
       
    while(controle_file_size <= a){
        //  data = data+img_binary[a];
    //  if(img_binary[a] != "\n"){
        
        data = data + img_binary[controle_file_size];
            controle_file_size++;
        //}
}
            a = controle_file_size + 512;       

        
return 0;
}



//Sends the image:
int data_send(std::string data){
    std::cout << "\nData send has been called";
            
              sent_message = "\nSending Image";
              send(client.socket, sent_message, strlen(sent_message), 0);                   
                            
                             sent_message = data.c_str();
                             send(client.socket, sent_message, strlen(sent_message), 0);
                                           
              sent_message = "\nThe image has been send";
              send(client.socket, sent_message, strlen(sent_message), 0); 
               

}

And to be sure that all the file has been sent, I created this logic on Int Main:


int main(){
    
    
    std::thread worker1(conectar, "127.0.0.1", "8080"); //COnnection thread
    
    
    std::cout << "\nPress any button to send the image";
    system("pause");
    
    std::thread worker2(data_send, data); //Data send
    
    while(controle_file_size < file_size){
        
    imgBinaryExtractor();
    std::cout << data;
    
        worker2.join(); //
}

    
    worker1.join();         
//  worker2.join(); 
    
    std::cout << "\nThe image has been sent" << std::endl;
}

In the server code:

This recives the 512 bites from the client and stores it into the "binario" variable:

while (1)
    {
        //memset(tempmsg, 0, DEFAULT_BUFLEN);

        if (new_client.socket != 0)
        {
            int iResult = recv(new_client.socket, tempmsg, DEFAULT_BUFLEN, 0);      
            
            std::cout << "\nSize of buffer is: " << strlen(tempmsg);
            if (iResult != SOCKET_ERROR)
            {
   
                if (strcmp("", tempmsg))
                    //msg = "PC filho #" + std::to_string(new_client.id) + ": " + tempmsg;
                    
                        std::cout << tempmsg;
                        
                        binario = tempmsg;
                        
                        
    binaryStorer(binario);

Later it calls this funcion to store the binary into a png file.

int binaryStorer(std::string binario){
    
    int i = 0;
    
    std::ofstream file2;
    const char* tfile = "passed-image.png";

    file2.open(tfile, std::ios::binary);


file2 << binario;
    file2.close();
    return 0;   
}

1 Answers1

2

This bit is wrong:

sent_message = data.c_str();
send(client.socket, sent_message, strlen(sent_message), 0);

data is a std::string which contains binary data, this binary data is likely to contain zero values scattered throughout. Then you grab the raw array out of the std::string and run strlen on it - a function that is designed to be used on C-style null-terminated text strings.

https://en.cppreference.com/w/cpp/string/byte/strlen

Returns the length of the given byte string, that is, the number of characters in a character array whose first element is pointed to by str up to and not including the first null character.

I hope I don't have to explain why this produces an incorrect result.

Also, strlen finds the length of a string by looping through it one character at a time, which is silly since you already have the length readily at hand. Try something like this instead:

send(client.socket, data.c_str(), data.size(), 0);

Edit: Per comment: What is a C-style null-terminated text string?

In C you typically save text strings in character arrays and access them through char*, unfortunately none of those can tell you how long the text they hold/point to is. So the convention is that all text strings are terminated with a null (\0) character. You can see this if you create a string-literal and then look at it in a debugger, for example "Hello" will show up as 'H','e','l','l','o','\0'.

This also means that all the C functions that work on C-strings will assume this style of data, and specifically strlen will look at this array: a,b,c,\0,d,e,f\0 - which contains 8 bytes - and tell you the the length is 3.

Frodyne
  • 3,547
  • 6
  • 16
  • I used `send(client.socket, data.c_str(), 512, 0);` and received the same 28 bits as before. (I'm new to C++ and programming, where could I read about C-style null-terminated text strings to understand why my code is incorrect?) – iumonyty Aug 11 '23 at 13:20
  • I'm sorry; I understand that I'm asking silly questions, but I really want to build knowledge about C++. I'm in high school, and this is my undergraduate thesis. – iumonyty Aug 11 '23 at 13:25
  • This answer also fails to mention the biggest defect in the shown code: the assumption that `send()` will send the requested amount of bytes, and not checking the return value. This will also end in tears. Unfortunately, Stackoverflow is not a C++ tutorial site or a help site, we only answer ***specific*** questions. You can "read about C-style null-terminated text string", and how to correctly use `send()` and `recv()`, in any good textbook that covers C++ fundamentals and network programming. – Sam Varshavchik Aug 11 '23 at 13:26
  • I added a quick explanation of null-terminated strings. Also, Sam is right - always check your return values. – Frodyne Aug 11 '23 at 13:49
  • For more info in the networking part, I can point you to "Beej's Guide to Network Programming": https://beej.us/guide/bgnet/html//index.html – Frodyne Aug 11 '23 at 13:51