Reputation: 55
I'm currently building a C/C++ application that sends and receives picture files over a network socket. However, when I send the file over the socket, the destination file has a slight byte-difference when compared to the source file.
In order for this application to function correctly, the destination (client) file must be identical, byte-wise, to the source (server) file.
Client code:
int client_app(int argc, char *argv[]) {
// create a socket
int network_socket;
network_socket = socket(AF_INET, SOCK_STREAM, 0);
// specify an address for the socket
struct sockaddr_in server_address;
server_address.sin_family = AF_INET;
server_address.sin_port = htons(9002);
server_address.sin_addr.s_addr = INADDR_ANY;
// connect returns an integer
int connection_status = connect(network_socket, (struct sockaddr *) &server_address, sizeof(server_address));
if (connection_status == -1) {
printf("Error making connection to remote socket \n\n");
}
// read picture byte array
printf("Reading picture byte array...\n");
char p_array[BUFSIZ];
// convert it back into a pic
printf("Converting byte array to DNG...\n");
FILE *image = fopen("out_compressed.GPR", "w");
int nb;
while ((nb = read(network_socket, p_array, BUFSIZ)) > 0) {
fwrite(p_array, 1, nb, image);
bzero(p_array, BUFSIZ);
}
fclose(image);
// and then close the socket
close(network_socket);
}
Server code:
int server_app(int argc, char *argv[]) {
char *process_argv[100];
*process_argv = *argv;
int process_argc = 0;
for (int i = 1; i < 6; i++) {
process_argv[i] = argv[i + 1];
process_argc++;
}
process(process_argc, process_argv);
// create the server socket
int server_socket;
server_socket = socket(AF_INET, SOCK_STREAM, 0);
// define the port number
int port = 9002;
// define the server address
struct sockaddr_in server_address;
server_address.sin_family = AF_INET;
server_address.sin_port = htons(port);
server_address.sin_addr.s_addr = INADDR_ANY;
// bind the socket to our specified IP and port
bind(server_socket, (struct sockaddr *) &server_address, sizeof(server_address));
// listen for connections on the socket
listen(server_socket, 5);
// create client socket for the server to send data to
int client_socket;
client_socket = accept(server_socket, nullptr, nullptr);
// get picture size
char *fpath = process_argv[4];
FILE *picture;
picture = fopen(fpath, "r");
int size;
fseek(picture, 0, SEEK_END);
size = ftell(picture);
fseek(picture, 0, SEEK_SET);
// send picture size
write(client_socket, &size, sizeof(size));
// send picture as byte array
char send_buffer[BUFSIZ];
int nb = fread(send_buffer, 1, sizeof(send_buffer), picture);
while (!feof(picture)) {
write(client_socket, send_buffer, nb);
nb = fread(send_buffer, 1, sizeof(send_buffer), picture);
}
// then close the sockets
close(server_socket);
close(client_socket);
}
When I receive a file on the client-side, it appears to be the same size, but I'm unable to perform certain compression operations on it, unlike the source file.
When running cmp
in my terminal to compare the source and destination files, I get the result:
compressed.GPR out_compressed.GPR differ: char 1, line 1
How can I get these files to be byte-wise identical?
Thanks!
Upvotes: 1
Views: 355
Reputation: 223689
There are two main errors.
First, the server writes the size of the file before the content, but the client starts reading the content right away, so the file size becomes part of the content on the client side. The client doesn't need the size, so six this by simply not sending the file size on the server side.
The second issue is in your use of feof
:
int nb = fread(send_buffer, 1, sizeof(send_buffer), picture);
while (!feof(picture)) {
write(client_socket, send_buffer, nb);
nb = fread(send_buffer, 1, sizeof(send_buffer), picture);
}
When fread
reads the last portion of the file, i.e. an amount smaller than the buffer size, the EOF flag is set. That means feof
returns true and you exit the loop before writing the last segment of the file to the socket.
A better way of handling this is loop while 1 or more bytes was read from the file:
int nb = fread(send_buffer, 1, sizeof(send_buffer), picture);
while (nb > 0) {
write(client_socket, send_buffer, nb);
nb = fread(send_buffer, 1, sizeof(send_buffer), picture);
}
In addition to this, you don't perform error checking on any of the functions you call. You should check the return value of all socket and file related functions and use perror
to print an error message if they fail.
Upvotes: 1
Reputation: 33932
write(client_socket, &size, sizeof(size));
wrote the size of the image file into the socket (but did not check for a successful write. Always check the return code to make sure you wrote what you thought you did.). The client makes no use of this information and lumps it into the file. Based on how the client is currently coded, the sockets are being closed immediately after finishing the file, you can discard the code computing and sending the length. When the socket is closed, the file is done. There is no need to send the length as a helper.
In addition, the image is almost certainly binary information. Opening the file with
FILE *image = fopen("out_compressed.GPR", "w");
and
picture = fopen(fpath, "r");
will open in text mode and possibly perform some conversions (most famous of these is \r\n
to \n
) and muck up the file. Open with "wb"
and "rb"
respectively.
Upvotes: 1
Reputation: 123260
In the client you send the size of the file and then the content. In the server you assume that only the content is sent, i.e. you store the initially send size information as content in the new file.
Apart from that you just assume that write will actually write all data given, which is not guaranteed. Thus you need to check the actual number of bytes written. And if you are on Windows you better open the files as binary (i.e. "rb" instead of "r", "wb" instead of "w") since you are dealing with binary data here.
Upvotes: 1