Transfer file in C delievers mangled data - c

I'm a newbie in C programming. I am writing a function where the client copies a file from the server. However, when I open my newly created file it contains a lot of additional characters. How can I prevent it from copying useless data?
Relevant sections of the server follow
if (file = fopen(buf, "r")){
//send the file
// while(fgets(buffer, 1024, file) != NULL){
// res = write(new_fd, &buffer, sizeof(buffer));
// }
while(!feof(file)){
fscanf(file,"%s",buffer);
write(new_fd, &buffer, sizeof(buffer));
}
fclose(file);
}
Relevant sections of the client follow
fp = fopen ("testfile", "w");
while(read(sockfd, &buffer, sizeof(buffer)) != -1){
fputs(buffer, fp);
}
fclose(fp);

Two things: First don't do while (!feof(...)), it doesn't work as you expect it to. The reason is that the EOF flag is not set until after a failed read operation, so you will call fscanf once when the file has already reached the end. Instead to while (fscanf(...) == 1).
Secondly, depending on how you declare buffer, don't use &buffer or sizeof(buffer). Neither in the sender or the receiver. If buffer is a pointer then &buffer will return a pointer to that pointer, and sizeof(buffer) will return the size of the pointer and not what it points to. Besides, if buffer is an array then it might not be completely filled by the input, so why send data you don't need? Only send strlen(buffer) + 1 bytes (the +1 is for the string terminator).
Oh and a third thing, don't use fscanf to read a line, use fgets instead. Or even better, to be more effective, use fread to fill the complete buffer and send it all in less calls.

read() does not null terminate it's buffer. fputs requires a null terminated buffer.
while(read(sockfd, &buffer, sizeof(buffer)) != -1){
fputs(buffer, fp);
You can add the terminator with something like this:
int n = 0;
char buffer[SOME_CONSTANT];
while((n = read(sockfd, buffer, sizeof(buffer - 1))) != -1){
buffer[n] = 0;
fputs(buffer, fp);
}
Note also the declaration and use of buffer vs &buffer in the call to read.
Finally, see all of Joachim Pileborg's suggestions!

Related

how to send a file using sockets in c [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
txt file from a client to a server. Right now, the file is sent to the server, but it's missing the content (empty file).
client.c
void send_file(char *filename, int sockfd)
{
FILE *fp;
int n;
char data[BUFFERLEN] = {0};
fp = fopen(filename, "r");
while (fgets(data, BUFFERLEN, fp) != NULL)
{
send(sockfd, data, sizeof(data), 0)
bzero(data, BUFFERLEN);
}
}
server.c
void receive_file(char *filename, int sockfd)
{
int n;
FILE *fp;
char buffer[BUFFERLEN];
fp = fopen(filename, "w");
while (1)
{
n = recv(sockfd, buffer, BUFFERLEN, 0);
if (n <= 0)
{
break;
return;
}
fprintf(fp, "%s", buffer);
bzero(buffer, BUFFERLEN);
}
return;
}
while (fgets(data, BUFFERLEN, fp) != NULL)
{
send(sockfd, data, sizeof(data), 0)
This is wrong. Not all lines have the size of BUFFERLEN. Don't send what you haven't read. Do not use fgets in this application. Use fread, and pass its return value back to send.
n = recv(sockfd, buffer, BUFFERLEN, 0);
fprintf(fp, "%s", buffer);
This is also wrong. buffer is not necessarily null-terminated. Do not use fprintf in this application, use fwrite, and pass the return value of recv back to it.
It also helps to open files in binary mode.
There are multiple fundamental bugs in both the client and the server.
while (fgets(data, BUFFERLEN, fp) != NULL)
A single line of text gets read into data, followed by:
send(sockfd, data, sizeof(data), 0)
Two bugs on this one line:
this sends the entire data buffer. If the text line was 80 characters, that's what fgets read, but BUFFERLEN is 8192, this is going to attempt to send 8192 characters, instead of 80, since sizeof(data) is BUFFERLEN.
The return value from send gets completely ignored. This is always wrong, with sockets. The way that sockets work, if you request to send() either 80, 8192, or any number of bytes, you have no guarantees whatsoever that the requested number of bytes was actually sent on the socket. The sending socket may, very well, be able to send only ten bytes. Or may be just one byte. The return value from send() indicates how many bytes were actually sent. You must adjust your sending logic accordingly. So, for example, if you fgetsed and send 80 characters, and send() told you that only ten went out on the socket, you will then need to try again to send the remaining 70 characters. It is your responsibility to do so. And, of course, there's no guarantee that all 70 characters will be sent on the 2nd try.
And now, for problems with the server:
n = recv(sockfd, buffer, BUFFERLEN, 0);
Here, you're checking the number of bytes received. This is correct, but then:
fprintf(fp, "%s", buffer);
%s requires a '\0' terminated string. If you guessed that you have no such guarantee from recv() you guessed correctly. You either need to make sure whatever you fprintf here is manually terminated by an extra '\0' character (and making sure that slapping on one in the buffer won't overrun it, corrupting memory), or use something else, like fwrite, perhaps.
All of the above bugs must be fixed in order for this to work correctly.

Incorrect fprintf results

In the code below, I am trying to read from a socket and store the results in a file.
What actually happens, is that my client sends a GET request to my server for a file.html. My server finds the file and writes the contents of it to the socket. Lastly my client reads the content from thread_fd and recreates the file.
For some reason the recreated file has less content than the original. I have located the problem to be some lines in the end, that are missing. When I use printf("%s", buffer) inside the while loop everything seems fine in STDOUT but my fprintf misses somewhat 3.000 bytes for a file of 81.000 bytes size.
#define MAXSIZE 1000
int bytes_read, thread_fd;
char buffer[MAXSIZE];
FILE* new_file;
memset(buffer, 0, MAXSIZE);
if((new_file = fopen(path, "wb+")) == NULL)
{
printf("can not open file \n");
exit(EXIT_FAILURE);
}
while ((bytes_read = read(thread_fd, buffer, MAXSIZE)) > 0)
{
fprintf(new_file, "%s", buffer);
if(bytes_read < MAXSIZE)
break;
memset(buffer, 0, MAXSIZE);
}
You read binary data from the socket that may or may not contain a \0 byte. When you then fprintf that data the fprintf will stop at the first \0 it encounters. In your case that is 3000 bytes short of the full file. If your file contains no \0 byte the fprintf will simply continue printing the ram contents until it segfaults.
Use write() to write the data back to the file and check for errors. Don't forget to close() the file and check that for errors too.
Your code should/could look like:
int readfile(int thread_fd, char *path)
{
unsigned int bytes_read;
char buffer[MAXSIZE];
int new_file;
if ((new_file = open(path, _O_CREAT|_O_BINARY,_S_IWRITE)) == -1) return -1;
while ((bytes_read = read(thread_fd, buffer, MAXSIZE)) > 0)
{
if (write(new_file, buffer, bytes_read)!= bytes_read) {
close(new_file);
return -2;
}
}
close(new_file);
return 0;
}
There are a few issues with your code that can cause this.
The most likely cause is this :
if(bytes_read < MAXSIZE)
break;
This ends the loop when read returns less than the requested amount of bytes. This is however perfectly normal behavior, and can happen eg. when not enough bytes are available at the time of the read call (it's reading from a network socket after all). Just let the loop continue as long as read returns a value > 0 (assuming the socket is a blocking socket - if not, you'll also have to check for EAGAIN and EWOULDBLOCK).
Additionally, if the file you're receiving contains binary data, then it's not a good idea to use fprintf with "%s" to write to the target file. This will stop writing as soon as it finds a '\0' byte (which is not uncommon in binary data). Use fwrite instead.
Even if you're receiving text (suggested by the html file extension), it's still not a good idea to use fprintf with "%s", since the received data won't be '\0' terminated.
This worked!
ps: I don't know if I should be doing this, since I am new here, but really there is no reason for negativity. Any question is a good question. Just answer it if you know it. Do not judge it.
#define MAXSIZE 1000
int bytes_read, thread_fd, new_file;
char buffer[MAXSIZE];
memset(buffer, 0, MAXSIZE);
if((new_file = open(path, O_RDONLY | O_WRONLY | O_CREAT)) < 0)
{
printf("can not open file \n");
exit(EXIT_FAILURE);
}
while ((bytes_read = read(thread_fd, buffer, MAXSIZE)) > 0)
write(new_file, buffer, bytes_read);
close(new_file);

why is this not writing (receiving) the correct number of Bytes?

I receive data from an ftp socket connection. The connection seems tio be fine but for some reason, I don't get the correct nmumber of Bytes written to my destination file.
My source file has a size of 18735004 Bytes and my algorithm writes 19713024 Bytes to the file. Now can this be?
The code I have:
if (ftpXfer ("3.94.213.53", "**", "******", NULL,
"RETR %s", "/home/ge", "ngfm.bin",
&ctrlSock, &dataSock) == ERROR)
return (ERROR);
pFile = fopen( "flash:/ngfm.bin", "wb" );
if ( pFile == NULL ) {
printf("fopen() failed!\n");
status = ERROR;
}
while ((nBytes = read (dataSock, buf, sizeof (buf))) > 0) {
cnt++;
n+=fwrite (buf , sizeof(char), sizeof(buf), pFile);
if(cnt%100==0)
printf(".");
}
fclose( pFile );
printf("%d Bytes written to flash:/ngfm.bin\n",n);
The screen output ended with:
19713024 Bytes writen to flash:/ngfm.bin
What's wrong here?
You are ignoring the nBytes return value from read(), and instead always writing sizeof buf bytes to the output. That's wrong, for partial reads (where nBytes is less than sizeof buf) you are injecting junk into the written stream.
The write should of course use nBytes, too.
Also: the write can fail, and write less than you requested, so you need to loop it until you know that all bytes have been written, or you get an error from it.
It seems you aren't putting your FTP server in binary mode, and it's transferring in ascii. This replaces every \n with a \r\n sequence.
Additionally, unwind's reply is correct as well.

Copying stdin to buffer

Working on a networking project and using select() and FD_ISSET to watch stdin and also TCP connections simultaneously. I can't seem to capture keyboard entry in a buffer so that I can process it. Here's what I have:
if (FD_ISSET(0, &read_set)) {
fprintf(stdout, "Keyboard input noted:\n");
size_t bytes = fread(buffer, sizeof(char), BUFFSIZE, stdin);
fwrite(buffer, sizeof(char), bytes, stdout);
fflush(stdout);
if (bytes < BUFFSIZE)
if (feof(stdin))
break;
fprintf(stdout, "buffer: %s\n", buffer);
}
The first printf statement outputs as soon as I hit the enter key, but the second one never fires. Can someone tell me what I am missing? Thanks!
EDIT: When I change size_t bytes = fread(buffer, sizeof(char), BUFFSIZE, stdin); to something like
size_t bytes = fread(buffer, sizeof(char), 2*sizeof(char), stdin);
and then type in something like aa<enter> I can force it to output, but this is way too small. I need a way to get it return from fread when the enter key is read.
I switched the fread line to
size_t bytes = read(0, buffer, BUFFSIZE)
and that gets past the problem of fread not returning. Unfortunately, this also seems to pick up the carriage return character, which gives me an extra byte at the end of my buffer that I need to remove. For example, if I type in 'aa' and then output bytes, it shows 3 not 2. Now I need to figure out how to solve that problem.
Any better answers are very welcome. Thanks to all.

C Language: popen() with fread()?

I've been stuck on this for a few days and it's getting really frustrating.
I'm using popen() to call a command line process and get its output and store it in a C string. I was using fgets() but it seems that breaks after a new line, so I'm using fread(). The only problem is that the returned C string is sometimes messed up.
Here's my code:
const char *cmd = "date";//This the shell command
char buf[BUFSIZ];//Output of the command
FILE *ptr;
int c;
if ((ptr = popen(cmd, "r")) != NULL)
while(fread(buf, sizeof(buf),1, ptr))
while ((c = getchar()) != EOF)
printf("output = %s", buf);
(void) pclose(ptr);
The final C string sometimes has weird characters in it that shouldn't be there, or sometimes no string is even available. Can anybody please help? ):
Edit: Here is what I was doing when using fgets() The Shell command can be anything that outputs text though. Not just "date."
if ((ptr = popen(cmd, "r")) != NULL)while (fgets(buf, BUFSIZ, ptr) != NULL)printf("output = %s", buf);(void) pclose(ptr);
fread doesn't insert a NUL terminator after what it reads. You need to check the return value to know how much it read, and only print that much. If you read with fread, you typically want to write the data with fwrite, something on this order:
long bytes;
while ((bytes=fread(buf, sizeof(buf), 1, ptr))>0)
fwrite(buf, bytes, 1, stdout);
Well, fgets is the right way to do it.
FILE *ptr;
if (NULL == (ptr = popen(cmd, "r"))) {
/* ... */
}
while(fgets(buf, sizeof(buf), ptr) != NULL) {
/* There is stuff in 'buf' */
}
I think the reason fgets wasn't working for you is that you were doing something wrong.
Now, here's why I think you are running into trouble with your current code:
You are not checking how much fread actually returned
You are reading with getchar and discarding stuff
You don't have a NUL terminator in the buffer
Get this right and it will all be better: fread might legally read less than you told it to.
The output from date doesn't include the '\0' (NUL) character you need to properly terminate the string. Keep track of the number of characters read and put in the NUL yourself.
Though really, you should be using fgets, getline or similar text-oriented functions to read from a program such as date. getline is especially easy (and safe since it does some memory management for you):
FILE *fp = popen("date", "r");
char *ln = NULL;
size_t len = 0;
while (getline(&ln, &len, fp) != -1)
fputs(ln, stdout);
free(ln);
pclose(fp);
Below is the correct way to use fread for process output with popen:
const char *cmd = "date";
char buf[BUFSIZ];
FILE *ptr;
if ((ptr = popen(cmd, "r")) != NULL) {
/* Read one byte at a time, up to BUFSIZ - 1 bytes, the last byte will be used for null termination. */
size_t byte_count = fread(buf, 1, BUFSIZ - 1, ptr);
/* Apply null termination so that the read bytes can be treated as a string. */
buf[byte_count] = 0;
printf("%s\n", buf);
}
(void) pclose(ptr);
As you can see, the primary problem is to correctly deal with null termination. The two size parameter of fread is also important, you have to let it read character by character. Note that in the case of popen, fread will only return 0 if the process has exited without giving any output. It will not return 0 if it takes a long time for the process to print anything.
If the output is larger than BUFSIZ, you can wrap fread with a while loop.

Resources