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
You have a number of problems:
"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.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 itioctl
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.ntohl(3)
and htonl(3)
functions to do these conversions for 4-byte values.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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With