Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sending Image (JPEG) through Socket in C Linux

I'm writing a small C program in order to be able to transfer an image file between two computers (from server to client both running linux) using TCP/IP sockets but there seems to be an error as my picture appears on the other sides corrupted.

The code for my server is as such:

#include<stdio.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>   
#include<unistd.h>  
#include<iostream>
#include<fstream>
#include<errno.h>

using namespace std;

int send_image(int socket){

FILE *picture;
int size, read_size;
char send_buffer[10240], verify;

picture = fopen("2.jpg", "r");
printf("Getting Picture Size\n");   

if(picture == NULL) {
   printf("Error Opening Image File");
} 

fseek(picture, 0, SEEK_END);
size = ftell(picture);
fseek(picture, 0, SEEK_SET);

//Send Picture Size
printf("Sending Picture Size\n");
write(socket, (void *)&size, sizeof(int));

if(read_size = read(socket, &verify , sizeof(char)) < 0) {
   puts("\nError Receiving Verification");
}


if(verify == '1'){
    printf("5\n");
    //Send Picture as Byte Array
    printf("Sending Picture as Byte Array\n");

    while(!feof(picture)) {

          //Read from the file into our send buffer
          read_size = fread(send_buffer, 1, sizeof(send_buffer)-1, picture);

          //Send data through our socket 
          write(socket, send_buffer, read_size);                        

          //Wait for the verify signal to be received 
          while(read(socket, &verify , sizeof(char)) < 0);

          if(verify != '1') {
             printf("Error Receiving the Handshake signal\n %s",&verify);
          }

          verify = '';

          //Zero out our send buffer
          bzero(send_buffer, sizeof(send_buffer));
   }
}
}

int main(int argc , char *argv[])
{
int socket_desc , new_socket , c, read_size,buffer = 0;
struct sockaddr_in server , client;
char *readin;

//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
    printf("Could not create socket");
}

//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8889 );

//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
    puts("bind failed");
    return 1;
}

puts("bind done");

//Listen
listen(socket_desc , 3);

//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);

if((new_socket = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c))){
    puts("Connection accepted");
}

fflush(stdout);

if (new_socket<0)
{
    perror("Accept Failed");
    return 1;
}

send_image(new_socket);

    close(socket_desc);
    fflush(stdout);
return 0;
}

The client side code which is receiving the data is as such:

 #include<stdio.h>
 #include<string.h>    //strlen
 #include<sys/socket.h>
 #include<sys/ioctl.h>
 #include<arpa/inet.h>    
 #include<unistd.h>
 #include<iostream>
 #include<errno.h>
 using namespace std;

 //This function is to be used once we have confirmed that an image is to be sent
 //It should read and output an image file
 int receive_image(int socket){

int buffersize = 0, recv_size = 0,size = 0, read_size, write_size;
char imagearray[10241],verify = '1';
FILE *image;

//Find the size of the image
read(socket, &size, sizeof(int));



//Send our verification signal
write(socket, &verify, sizeof(char));
//Make sure that the size is bigger than 0
if(size <= 0 ){
    printf("Error has occurred. Size less than or equal to 0\n");
    return -1;
}

image = fopen("2.jpg", "w");

if( image == NULL) {
    printf("Error has occurred. Image file could not be opened\n");
    return -1;
}

//Loop while we have not received the entire file yet
while(recv_size < size) {
    ioctl(socket, FIONREAD, &buffersize); 

    //We check to see if there is data to be read from the socket    
    if(buffersize > 0 ) {

        if(read_size = read(socket,imagearray, buffersize) < 0){
            printf("%s", strerror(errno));
        }

        //Write the currently read data into our image file
        write_size = fwrite(imagearray,1,(buffersize), image);

        if(write_size != buffersize) {
          printf("write and buffersizes wrong");
        }

        if(read_size !=write_size) {
            printf("error in read write");
        }

        //Increment the total number of bytes read
        recv_size += read_size;

                    //Send our handshake verification info
        write(socket, &verify, sizeof(char));

    }
 }

fclose(image);
printf("Image successfully Received!\n");
return 1;
}

int main(int argc , char *argv[])
{

int socket_desc;
struct sockaddr_in server;
char *parray;


//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);

if (socket_desc == -1) {
    printf("Could not create socket");
}

memset(&server,0,sizeof(server));
server.sin_addr.s_addr = inet_addr("10.42.0.1");
server.sin_family = AF_INET;
server.sin_port = htons( 8889 );

//Connect to remote server
if (connect(socket_desc , (struct sockaddr *)&server , sizeof(server)) < 0) {
    cout<<strerror(errno);
    close(socket_desc);
    puts("Connect Error");
    return 1;
}

puts("Connected\n");

receive_image(socket_desc);

close(socket_desc);

return 0;
}

Can anyone give me a hand with this? I can't see to figure out this error for the life of me.

EDIT: I've changed the fwrites and freads back into regular write and read and it still sends a corrupted image

like image 801
user1721182 Avatar asked Mar 16 '13 03:03

user1721182


2 Answers

You have a number of problems:

  • You need to open the file in binary mode ("rb" for reading, "wb" for writing), not the default text mode. On Windows (and any other systems which do line ending translation), the stdio library converts LFs (bytes 0x0A) into CRLF pairs (the two bytes 0x0D 0x0A) when writing, and it does the inverse translation when reading. For non-text data like JPEG files, this corrupts the data.
  • There's no need to be sending your "handshake" bytes after each send. TCP/IP already handles acknowledgements/resends/flow control/etc. You can assume that as long as send()/write() returns a positive value, then that many bytes were received by the other peer.
  • send()/write() may not send all of the data you ask it to—they may do a partial send. If that happens, you need to keep trying to send the rest of the buffer in a loop.
  • sizeof(char) is guaranteed to be 1 by the C language standard, there's rarely a need to say sizeof(char) when instead your code will be much clearer without it
  • In the client code, there's no need to use that ioctl to determine how much data can be read without blocking because you're just looping again—your code will spin at 100% CPU while there's no data available. Just let the read() call block. If you're running this code on a laptop, your battery will thank you.
  • Likewise, the client will almost definitely be getting partial reads, you're not going to receive the whole file in a single call. You need to write out whatever data you get, then loop and receive again.
  • When you send the image size over the socket at the start, you might get a different value on the client if the two systems are not of the same endianness. In order to make your code bulletproof, you need to convert the data to network order (big-endian) when sending it, then convert it back to host (native) order after receiving it. You can use the ntohl(3) and htonl(3) functions to do these conversions for 4-byte values.
like image 113
Adam Rosenfield Avatar answered Oct 27 '22 00:10

Adam Rosenfield


Works nicely now.

Best,

Mario.

Client:

#include<stdio.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>   
#include<sys/ioctl.h>
#include<unistd.h>  
#include<iostream>
#include<fstream>
#include<errno.h>
using namespace std;

//This function is to be used once we have confirmed that an image is to be sent
//It should read and output an image file

int receive_image(int socket)
{ // Start function 

int buffersize = 0, recv_size = 0,size = 0, read_size, write_size, packet_index =1,stat;

char imagearray[10241],verify = '1';
FILE *image;

//Find the size of the image
do{
stat = read(socket, &size, sizeof(int));
}while(stat<0);

printf("Packet received.\n");
printf("Packet size: %i\n",stat);
printf("Image size: %i\n",size);
printf(" \n");

char buffer[] = "Got it";

//Send our verification signal
do{
stat = write(socket, &buffer, sizeof(int));
}while(stat<0);

printf("Reply sent\n");
printf(" \n");

image = fopen("capture2.jpeg", "w");

if( image == NULL) {
printf("Error has occurred. Image file could not be opened\n");
return -1; }

//Loop while we have not received the entire file yet


int need_exit = 0;
struct timeval timeout = {10,0};

fd_set fds;
int buffer_fd, buffer_out;

while(recv_size < size) {
//while(packet_index < 2){

    FD_ZERO(&fds);
    FD_SET(socket,&fds);

    buffer_fd = select(FD_SETSIZE,&fds,NULL,NULL,&timeout);

    if (buffer_fd < 0)
       printf("error: bad file descriptor set.\n");

    if (buffer_fd == 0)
       printf("error: buffer read timeout expired.\n");

    if (buffer_fd > 0)
    {
        do{
               read_size = read(socket,imagearray, 10241);
            }while(read_size <0);

            printf("Packet number received: %i\n",packet_index);
        printf("Packet size: %i\n",read_size);


        //Write the currently read data into our image file
         write_size = fwrite(imagearray,1,read_size, image);
         printf("Written image size: %i\n",write_size); 

             if(read_size !=write_size) {
                 printf("error in read write\n");    }


             //Increment the total number of bytes read
             recv_size += read_size;
             packet_index++;
             printf("Total received image size: %i\n",recv_size);
             printf(" \n");
             printf(" \n");
    }

}


  fclose(image);
  printf("Image successfully Received!\n");
  return 1;
  }

  int main(int argc , char *argv[])
  {

  int socket_desc;
  struct sockaddr_in server;
  char *parray;


  //Create socket
  socket_desc = socket(AF_INET , SOCK_STREAM , 0);

  if (socket_desc == -1) {
  printf("Could not create socket");
  }

  memset(&server,0,sizeof(server));
  server.sin_addr.s_addr = inet_addr("10.0.0.30");
  server.sin_family = AF_INET;
  server.sin_port = htons( 8889 );

  //Connect to remote server
  if (connect(socket_desc , (struct sockaddr *)&server , sizeof(server)) < 0) {
  cout<<strerror(errno);
  close(socket_desc);
  puts("Connect Error");
  return 1;
  }

  puts("Connected\n");

  receive_image(socket_desc);

  close(socket_desc);

  return 0;
  }

Server:

   #include<stdio.h>
   #include<string.h>
   #include<sys/socket.h>
   #include<arpa/inet.h>   
   #include<unistd.h>  
   #include<iostream>
   #include<fstream>
   #include<errno.h>

   using namespace std;

   int send_image(int socket){

   FILE *picture;
   int size, read_size, stat, packet_index;
   char send_buffer[10240], read_buffer[256];
   packet_index = 1;

   picture = fopen("capture.jpeg", "r");
   printf("Getting Picture Size\n");   

   if(picture == NULL) {
        printf("Error Opening Image File"); } 

   fseek(picture, 0, SEEK_END);
   size = ftell(picture);
   fseek(picture, 0, SEEK_SET);
   printf("Total Picture size: %i\n",size);

   //Send Picture Size
   printf("Sending Picture Size\n");
   write(socket, (void *)&size, sizeof(int));

   //Send Picture as Byte Array
   printf("Sending Picture as Byte Array\n");

   do { //Read while we get errors that are due to signals.
      stat=read(socket, &read_buffer , 255);
      printf("Bytes read: %i\n",stat);
   } while (stat < 0);

   printf("Received data in socket\n");
   printf("Socket data: %c\n", read_buffer);

   while(!feof(picture)) {
   //while(packet_index = 1){
      //Read from the file into our send buffer
      read_size = fread(send_buffer, 1, sizeof(send_buffer)-1, picture);

      //Send data through our socket 
      do{
        stat = write(socket, send_buffer, read_size);  
      }while (stat < 0);

      printf("Packet Number: %i\n",packet_index);
      printf("Packet Size Sent: %i\n",read_size);     
      printf(" \n");
      printf(" \n");


      packet_index++;  

      //Zero out our send buffer
      bzero(send_buffer, sizeof(send_buffer));
     }
    }

    int main(int argc , char *argv[])
    {
      int socket_desc , new_socket , c, read_size,buffer = 0;
      struct sockaddr_in server , client;
      char *readin;

      //Create socket
      socket_desc = socket(AF_INET , SOCK_STREAM , 0);
      if (socket_desc == -1)
      {
         printf("Could not create socket");
      }

      //Prepare the sockaddr_in structure
      server.sin_family = AF_INET;
      server.sin_addr.s_addr = INADDR_ANY;
      server.sin_port = htons( 8889 );

      //Bind
     if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
     {
       puts("bind failed");
       return 1;
     }

     puts("bind done");

     //Listen
     listen(socket_desc , 3);

      //Accept and incoming connection
      puts("Waiting for incoming connections...");
      c = sizeof(struct sockaddr_in);

     if((new_socket = accept(socket_desc, (struct sockaddr *)&client,(socklen_t*)&c))){
puts("Connection accepted");
         }

    fflush(stdout);

    if (new_socket<0)
    {
      perror("Accept Failed");
      return 1;
    }

    send_image(new_socket);

    close(socket_desc);
    fflush(stdout);
    return 0;
    }
like image 9
mmirand6 Avatar answered Oct 26 '22 22:10

mmirand6