I'm trying to send an image file through a TCP socket in C, but the image isn't being reassembled correctly on the server side. I was wondering if anyone can point out the mistake?
I know that the server is receiving the correct file size and it constructs a file of that size, but it isn't an image file.
Client
//Get Picture Size
printf("Getting Picture Size\n");
FILE *picture;
picture = fopen(argv[1], "r");
int size;
fseek(picture, 0, SEEK_END);
size = ftell(picture);
//Send Picture Size
printf("Sending Picture Size\n");
write(sock, &size, sizeof(size));
//Send Picture as Byte Array
printf("Sending Picture as Byte Array\n");
char send_buffer[size];
while(!feof(picture)) {
fread(send_buffer, 1, sizeof(send_buffer), picture);
write(sock, send_buffer, sizeof(send_buffer));
bzero(send_buffer, sizeof(send_buffer));
}
Server
//Read Picture Size
printf("Reading Picture Size\n");
int size;
read(new_sock, &size, sizeof(int));
//Read Picture Byte Array
printf("Reading Picture Byte Array\n");
char p_array[size];
read(new_sock, p_array, size);
//Convert it Back into Picture
printf("Converting Byte Array to Picture\n");
FILE *image;
image = fopen("c1.png", "w");
fwrite(p_array, 1, sizeof(p_array), image);
fclose(image);
Edit: Fixed sizeof(int) in server code.
you need to seek to the beginning of the file before you read
fseek(picture, 0, SEEK_END);
size = ftell(picture);
fseek(picture, 0, SEEK_SET);
or use fstat to get the file size.
Check fread and fwrite syntax:
size_t fread(void *ptr, size_t size, size_t n, FILE *fp);
size_t fwrite(const void *ptr, size_t size, size_t n, FILE *fp);
In your case correct statement should be:
fread(send_buffer, sizeof(send_buffer), 1, picture);
fwrite(p_array, sizeof(p_array), 1,image);
Although it's an old post, I must highlight a few problems in the original code :
feof(picture) is always false after fopen. You must always make a read before calling feof
read(new_sock, p_array, size) is not guaranteed to read size bytes, it depends on the value of size, network load, server load,...
A correct (at least more robust) version would be :
//Send Picture as Byte Array (without need of a buffer as large as the image file)
printf("Sending Picture as Byte Array\n");
char send_buffer[BUFSIZE]; // no link between BUFSIZE and the file size
int nb = fread(send_buffer, 1, sizeof(send_buffer), picture);
while(!feof(picture)) {
write(sock, send_buffer, nb);
nb = fread(send_buffer, 1, sizeof(send_buffer), picture);
// no need to bzero
}
Same problem on server side :
//Read Picture Byte Array
printf("Reading Picture Byte Array\n");
char p_array[size];
char* current = p_array;
int nb = read(new_sock, current, size);
while (nb >= 0) {
current = current + nb;
nb = read(new_sock, current, size);
}
On server side you can avoid the creation of a buffer as large a image file (which might be a problem with large images) :
//Read Picture Byte Array and Copy in file
printf("Reading Picture Byte Array\n");
char p_array[BUFSIZE];
FILE *image = fopen("c1.png", "w");
int nb = read(new_sock, p_array, BUFSIZE);
while (nb > 0) {
fwrite(p_array, 1, nb, image);
nb = read(new_sock, p_array, BUFSIZE);
}
fclose(image);
Related
I try to transfer a data size of around 100MB over a TCP ipv4 connection socket.
I calculate the CheckSum in the client before sending it to see what the checksum is.
After sending the data file to the server and the server writes it to a new file I calculate again the checksum and I can see a differents.
I think is probably with my send and receive functions.
The Sender function used in CLIENT :
void send_file(FILE *fp, int sockfd) {
int n;
char data[SIZE] = {0};
while (fgets(data, SIZE, fp) != NULL) {
if (send(sockfd, data, sizeof(data), 0) == -1) {
perror("[-]Error in sending file.");
exit(1);
}
bzero(data, SIZE);
}
}
The Writer function the use in the SERVER:
void write_file(int sockfd, char *filename) {
int n;
FILE *fp;
//char *filename = "new_data.txt";
char buffer[SIZE];
fp = fopen(filename, "w");
while (1) {
n = recv(sockfd, buffer, SIZE, 0);
if (n <= 0) {
break;
return;
}
fprintf(fp, "%s", buffer);
bzero(buffer, SIZE);
}
}
fgets() and fprintf() are used for reading and writing zero-terminated strings, not arbitrary binary data. fread() and fwrite() are your friends here. Something like:
Client:
#define CHUNK_SIZE 1024
char buffer[CHUNK_SIZE];
while ((num_bytes = fread(buffer, 1, CHUNK_SIZE, fp)) > 0)
{
send(sockfd, buffer, num_bytes, 0);
}
Server:
// Same chunk size and buffer as above
while ((num_bytes = recv(sock, buffer, CHUNK_SIZE, 0)) > 0)
{
fwrite(buffer, 1, num_bytes, fp);
}
Technically fwrite() and send() can write less bytes than you ask them to, and you really should loop until all bytes are written.
You should also technically open your files with modes "rb" and "wb" for binary files.
I am using Linux. C2 (client) should read and send contents of file F1.txt to C1 (server) in successive messages of size 256 bytes (or remaining size of the file when you get near the end of the file)
First, I get the F1.txt size in bytes and sent it to the server c1.
fseek(fp, 0L, SEEK_END); //move fp to the end of the file
int fileLen = ftell(fp); // get the file size because ftell returns the current value of the position indicator
fseek(fp, 0L, SEEK_SET); //seek back to the begin of the file
write(sock, &fileLen, sizeof(int)); //send file size to server c1
Next, I send the file in successive 256 bytes by a for loop. The client c2 code is
char buffer[BUF_SIZE] = {0}; //BUF_SIZE=256
for (int i = 0; i <((fileLen/256) +1); i++)
{
memset(buffer, 0, sizeof(buffer)); //clear buffer
fread(buffer, 1, i <(fileLen/256)?(sizeof(buffer)):(fileLen%256), fp); // read BUF_SIZE elements, each one with a size of 1 bytes,
printf("Message client_c2 sent: %s\n", buffer);
write(sock, buffer, i <(fileLen/256)?sizeof(buffer):(fileLen%256));
usleep(1000);
}
fclose(fp);
The server c1 read the filesize, and read the socket within the for loop:
int receiveFileLen;
read(clnt_sock, &receiveFileLen, sizeof(int));
printf("clinet_c2 file size is %d\n",receiveFileLen);
for (int i = 0; i < ((receiveFileLen/256) +1); i++)
{
memset(buffer, 0, sizeof(buffer)); //clear buffer
read(clnt_sock, buffer, i < (receiveFileLen/256) ? sizeof(buffer) :(receiveFileLen%256) );
printf("buffer that writen into file is %s\n",buffer);
fwrite(buffer, strlen(buffer), 1,fp);
}
(1) The problem is in client c2 code's fread(fp), when i printf("Message client_c2 sent: %s\n", buffer); I found every time at the end of buffer, there is a wrong char (square shape in which shows 0002.)
(2) In server c1 code. I read the socket and fwrite it to a local txt. fwrite(buffer, strlen(buffer), 1,fp); I tried strlen(buffer)+1, but it gives me wrong chars ^B in the txt, so I use strlen(buffer).
(3) In server c1 code, I cannot read the full content of the remaining size of the file when I get near the end of the file. In the for loop, I get the previous iterations correctly written into txt, but when comes to the last iteration, i = (receiveFileLen/256) in other words, only part of socket content is read and fwrite into the txt, there is still chars that should be read remaining in the socket.
Thank you for your help!
I need to transfer .txt file using sockets. I try this:
Server:
#define CHUNKSIZE 1024
FILE* fd = fopen("download.txt", "rb");
size_t rret, wret;
int bytes_read;
char buffer[CHUNKSIZE];
while (!feof(fd)) {
if ((bytes_read = fread(&buffer, 1, sizeof(buffer), fd)) > 0)
send(Connections[index], buffer, bytes_read, 0);
else
break;
}
fclose(fd);
Client:
char text[1024];
size_t datasize;
FILE* fd = fopen("download.txt", "wb");
while (true)
{
datasize = recv(Connection, (char*)&text, sizeof(text), NULL);
fwrite(&text, 1, datasize, fd);
}
fclose(fd);
But the client does not write anything to download.txt
What could be problem? (I am not pasting the full code because sending messages (recv, send) works well)
I am trying to send a file from client to server. It sometime worksand sometime don't. when first time trying to send file, it sends corrupt file and the file side formed at server side is double of its size. But file successful transfers for all attempts after first attempt. Can anyone help me with this ?
Client.c
message msg;
msg.type = SEND_FILE;
char *username, *filename;
username = strtok(input+6, " ");
filename = strtok(NULL, "");
//Get Picture Size
printf("Getting Picture Size\n");
FILE *picture;
picture = fopen(filename, "r");
int size;
fseek(picture, 0, SEEK_END);
size = ftell(picture);
fseek(picture, 0, SEEK_SET);
//Send Picture Size
printf("Getting Picture Size\n");
sprintf(msg.data, "%d", size);
strncpy(msg.username, username, 20);
if(send(connection->socket, &msg, sizeof(message), 0) < 0)
{
perror("Send failed");
exit(1);
}
//Send Picture as Byte Array
printf("Sending Picture as Byte Array\n");
char send_buffer[size+1];
fread(send_buffer, 1, sizeof(send_buffer), picture);
write(connection->socket, send_buffer, sizeof(send_buffer));
bzero(send_buffer, sizeof(send_buffer));
server.c
//Read Picture Size
printf("Reading Picture Size\n");
int size = atoi(message_text);
//Read Picture Byte Array
printf("Reading Picture Byte Array\n");
char p_array[size];
printf("Converting Byte Array to Picture %d\n", size);
FILE *image;
image = fopen("c4.png", "w");
int readSize = 0;
while (readSize < size) {
readSize = readSize + read(clients[sender].socket, p_array, size);
fwrite(p_array, 1, sizeof(p_array), image);
}
fclose(image);
For starters:
You don't want to store the same number of bytes on every fwrite()
fwrite(p_array, 1, sizeof(p_array), image);
but only the number of bytes actually read.
sizeof(p_array) returns the size of p_array, which is size times the size of a char. The latter is defined as being 1.
Besides this the call to read() completely lacks error checking, along with the test whether the other side shut down the connection. This is not leading far.
To fix this you could do:
#include <errno.h> /* for errno */
...
size_t size = atoi(message_text);
printf("Reading Picture Byte Array\n");
char p_array[size];
size_t readSize = 0;
while (readSize < size) {
ssize_t result = read(clients[sender].socket, p_array, size); /* Mind the ssize_t, it's *not* size_t! */
if (0 >= result)
{
if (0 == result)
{
fprintf(stderr, "The other end gracefully shut down the connection.\n");
break;
}
else
{
if (EINTR == errno) /* got interrupted, start over */
{
continue;
}
if (EAGAIN == errno) /* in case reading from a non-blocking socket: no data available, start over */
{
continue;
}
/* Something went wrong unrecoverable. */
perror("read() failed");
break;
}
}
else
{
fwrite(p_array, 1, result, image);
/* Also add error checking here! */
readSize += result;
}
}
Let me start by saying this is a homework assignment and I am not a c programmer. I have been working on this for days and I am stuck. I have read the beej guide from cover to cover and have been searching google for a week, it's time to ask for help. I have a client-server TCP socket application that sends and receives messages as expected, now I need to implement simple file upload/download functionality.
The code below almost works but it adds 4 bytes to the beginning of the copied file, two non-printable characters followed by \00\00 and the client no longer responds.
The client is connected by a non-blocking socket using the select command.
I know there is lots of room for improvement but can someone help me get started?
// Server
void put (int sockfd, char *localfile) {
// Get file Size
FILE *file;
int size;
file = fopen(localfile, "rb");
fseek(file, 0, SEEK_END);
size = ftell(file);
fseek(file, 0, SEEK_SET);
//Send file Size
write(sockfd, &size, sizeof(int));
//Send file as Byte Array
char send_buffer[size];
memset(send_buffer, 0, sizeof(send_buffer));
//while(!feof(file)) {
// fread(send_buffer, 1, sizeof(send_buffer), file);
// write(sockfd, send_buffer, sizeof(send_buffer));
// memset(send_buffer, 0, sizeof(send_buffer));
//}
int sent;
while((sent = fread(send_buffer, sizeof(char), sizeof(send_buffer), file)) > 0)
{
if(send(sockfd, send_buffer, sent, 0) < 0)
{
fprintf(stderr, "[Server] ERROR: Failed to send file %s. (errno = %d)\n", localfile, errno);
break;
}
memset(send_buffer, 0, sizeof(send_buffer));
}
fclose(file);
}
//Client
void get(int sockfd, char *remotefile) {
FILE *file;
int size;
//Read file Size
read(sockfd, &size, sizeof(int));
//Read file Byte Array
char p_array[size];
memset(&p_array, 0, sizeof(p_array));
read(sockfd, p_array, size);
//Convert it Back into file
file = fopen(remotefile, "wb");
fwrite(p_array, 1, sizeof(p_array), file);
fclose(file);
}
You are making the usual error of ignoring the read count when reading the socket, and assuming that each read fills the buffer. You can't assume that.
Your send loop doesn't make that mistake. So, use that as a model, but redo it for receiving so as to use read() instead of fread(). You should then see that there's no need to allocate a buffer the size of the file, and there is therefore no need to send the filesize ahead of the file, unless you're planning on keeping the connection open for another purpose.
There's also no reason for any of the memset() calls.