Transferring a JPEG file between processes in C - c

I'm writing a server with a client and I'm having issues transferring images. I tried to fread the file on a buffer, to send the buffer to the client and to fwrite the buffer on a new file and it worked! Now it doesn't work anymore and I don't know why, when I check the new file, my image opener says that it's impossible to open the JPEG file etc.
My reading code:
int fd=open(pathname, O_RDONLY, 0666);
struct stat fileStat;
if(fstat(fd,&fileStat) < 0)
{
perror("\nfilestat\n");
exit(-1);
}
int fileSize=(int)fileStat.st_size;
//printf("File Size: \t\t%d bytes\n",fileSize);
FILE *f=fdopen(fd, "rb");
if(f==NULL)
{
perror("\nfopen\n");
exit(-1);
}
void *buf=malloc(fileSize);
if(buf==NULL)
{
perror("\nmalloc\n");
return -1;
}
int FR=fread(buf, fileSize, 1, f);
if(FR<0)
{
perror("\nfread\n");
exit(-1);
}
Then I write the body on my server message:
punt+=sprintf(punt, "%s\r\n", (char *)buf);
And after the client has extracted it from the received message, I fwrite it on a new file:
char *clientfile="./qui.jpg";
int fdbis=open(clientfile, O_WRONLY|O_CREAT|O_TRUNC, 0666);
if(fdbis<=0)
{
perror("\nopen 2\n");
exit(-1);
}
FILE *fbis=fdopen(fdbis, "wb");
if(fbis==NULL)
{
perror("fdopen");
exit(-1);
}
int WR=fwrite((void*)buf, strlen(buf), 1, fbis);
if(WR<=0)
{
perror("\nfwrite\n");
exit(-1);
}
I'm not pasting my server-client code because the code above doesn't work either on a test program without sending/receiving and without string extraction, so the problem has to be in it.
I'm programming in C, with a Posix system, and compiling with gcc.
Thank you for your attention.

Since a jpeg file is binary, you cannot use string function to manipulate it.
strlen(buf) will return the length till the first null termination.
use memcpy.

Related

When I program in Linux using C, I use the open or creat functions and end up behaving differently

//error handle
void my_err(const char* errno_string,int line){
fprintf(stderr,"line:%d ",line);
perror(errno_string);
exit(1);
}
//self-definded read data function
int my_read(int fd){
int len;
int ret;
int i;
char read_buf[64];
//get length of file and keep point of file at the srart
if(lseek(fd,0,SEEK_END) == -1){
my_err("lseek",__LINE__);
}
if((len = lseek(fd,0,SEEK_CUR)) == -1){
my_err("lseek",__LINE__);
}
if(lseek(fd,0,SEEK_SET) == -1){
my_err("lseek",__LINE__);
}
printf("len:%d\n",len);
//read data
if((ret = read(fd,read_buf,len)) < 0){
my_err("read",__LINE__);
}
//print data
for(i = 0;i<len;i++){
printf("%c",read_buf[i]);
}
printf("\n");
return ret;
}
int main()
{
int fd;
char write_buf[32] = "hello boy!";
//create example2 in current directory
if((fd = creat("example2.c",S_IRWXU)) == -1){
// if((fd = open("example2.c",O_RDWR|O_CREAT|O_TRUNC,S_IRWXU)) == -1){
my_err("open",__LINE__);
}else{
printf("craete file success\n");
}
//write data
if(write(fd,write_buf,strlen(write_buf)) != strlen(write_buf)){
my_err("write",__LINE__);
}
my_read(fd);
//Spacing of presentation files
printf("/*------------*/\n");
if(lseek(fd,10,SEEK_END) == -1){
my_err("lseek",__LINE__);
}
if(write(fd,write_buf,strlen(write_buf)) != strlen(write_buf)){
my_err("write",__LINE__);
}
my_read(fd);
close(fd);
return 0;
}
Line 43 is this part of main
//create example2 in current directory
if((fd = creat("example2.c",S_IRWXU)) == -1){
my_err("open",__LINE__);
}else{
printf("craete file success\n");
}
When I use creat, I get an error line:43 read: Bad file descriptor, but I get the correct result with open. Shouldn't both functions return file descriptors? Why should creat return the wrong file descriptor
When I use creat, I get an error line:43 read: Bad file descriptor, but I get the correct result with open. Shouldn't both functions return file descriptors? Why should creat return the wrong file descriptor
Shouldn't both functions return file descriptors?
They should and they do.
Why should creat return the wrong file descriptor
It shouldn't and it doesn't. read fails with Bad file descriptor error, not creat.
creat opens file write-only, so you can't read from it. It's a bad file descriptor if you want to read from it.
The call creat(path, mode) behaves the same as the call open(path, O_CREAT | O_WRONLY | O_TRUNC, mode). On success, the file is opened for writing only. The file descriptor passed to read needs to be open for either reading and writing or for reading only. If the file descriptor is open for writing only, calls to read with that file descriptor will fail. When read fails, the error number EBADF means that the file descriptor is not a valid file descriptor open for reading.

Issue with program involving sockets and client-server communication in C

I am working on a program in C that involves client-server connections and communication between the two parties.
The program involves the client sending a letter to the server and the server getting the letter. The server then searches through the current file directory (in linux) for a file beginning with that letter and sends the client the number of bytes of the file and the text of the file.
The overall program is very long and for the assignment the instructor already did much of the code such as setting up the sockets and creating the entire program for the client side of operations.
For the server side I had to write code for:
getting the file descriptor from the passed memory and casting it
-getting the letter from the client
-Attempting to open the current directory
-Iterating through the directory looking for a file that starts with the letter
-Attempting to open the file and sending the size of the file and number of bytes of file to the client in network endian
-Closing the file and directory after finishing
-Error checking: there are error checking statements if the directory cannot be opened, the file cannot be opened, or no matching file is found
The following is my code with comments
void* handleClient (void* vPtr
)
{
// I. Application validity check:
int fd = *((int *) vPtr);
//casting vPtr to an int//
free(vPtr);
// II. Handle the client:
char buffer[BUFFER_LEN+1];
read(fd, buffer, BUFFER_LEN+1);
//read the letter into a buffer//
const char* dirNamePtr = ".";
DIR* dirPtr = opendir(dirNamePtr);
// Open the current directory
if (dirPtr == NULL)
{
int toSend = htonl(CANT_READ_DIR_CODE);
write(fd,&toSend,sizeof(toSend));
printf("Cannot read directory\n");
return(NULL);
}
// If current directory cannot be opened, it sends a error message in network // endian to the client
struct dirent* entryPtr;
char path[BUFFER_LEN];
struct stat statBuffer;
//implements struct dirent to get info on the directory
//iterates through the directory
while ((entryPtr=readdir(dirPtr)) != NULL)
{
stat(entryPtr->d_name, &statBuffer);
//puts in metaddata of the current directory into statbuffer
if (!S_ISREG(statBuffer.st_mode))
continue;
//if the entry is not a file, continue
// if the first letter of the file is not the character received from the //client, send an error mesage
if(entryPtr->d_name[0]!=buffer[0]) {
int toSend2 = htonl(NO_MATCH_CODE);
write(fd,&toSend2,sizeof(toSend2));
printf("No matching file\n");
return(NULL);
}
int ab;
int numRead;
int numBytes;
char buffer[BUFFER_LEN];
//open the file and send bytes of file and file size to client
if (entryPtr->d_name[0]==buffer[0] &(S_ISREG(statBuffer.st_mode)))
{
ab=open(entryPtr->d_name,O_RDONLY,0660);
if(ab<0) {
int toSend3 = htonl(CANT_READ_FILE_CODE);
write(fd,&toSend3, sizeof(toSend3));
printf("Cannot read <filename>\n");
return(NULL);
}
numBytes=htonl(statBuffer.st_size);
write(fd, &numBytes, sizeof(numBytes));
printf("Sending %s, %d bytes\n",entryPtr >d_name,statBuffer.st_size);
while((numBytes=read(ab,buffer,BUFFER_LEN))>0)
{
printf("We read %d bytes\n", numBytes);
write(fd, buffer, numBytes);
}
//close the fiel
close(ab);
}
break;
//leave the loop
}
// III. Finished:
//
closedir(dirPtr);
return(NULL);
}
My code compiles but does not send the file to the client when I try running it. I have tried several different letters and it has not worked for any of them. I do not quite know what the issue is which makes it difficult to fix my mistakes.
I am not asking for the answer or anything, just help in seeing where I am wrong. I appreciate any help.
Your logic for when to send vs. when to send no-file status seems wrong. I think it should be like this (fair warning, I didn't test this, or even compile it beyond basic syntax checking, but you should get the idea):
void* handleClient(void* vPtr)
{
// I. Application validity check:
int fd = *((int *) vPtr);
free(vPtr);
// II. Handle the client:
char buffer[BUFFER_LEN+1];
read(fd, buffer, BUFFER_LEN+1);
//read the letter into a buffer//
const char* dirNamePtr = ".";
DIR* dirPtr = opendir(dirNamePtr);
// Open the current directory
if (dirPtr == NULL)
{
int toSend = htonl(CANT_READ_DIR_CODE);
write(fd,&toSend,sizeof(toSend));
printf("Cannot read directory\n");
return(NULL);
}
struct dirent* entryPtr;
char path[BUFFER_LEN];
struct stat statBuffer;
//implements struct dirent to get info on the directory
//iterates through the directory
while ((entryPtr=readdir(dirPtr)) != NULL)
{
stat(entryPtr->d_name, &statBuffer);
//puts in metaddata of the current directory into statbuffer
// if this isn't a regular file OR the first char doesn't match...
if (!S_ISREG(statBuffer.st_mode) || entryPtr->d_name[0]!=buffer[0])
continue;
int ab;
int numRead;
int numBytes;
char buffer[BUFFER_LEN];
//open the file and send bytes of file and file size to client
ab = open(entryPtr->d_name,O_RDONLY,0660);
if(ab<0) {
int toSend3 = htonl(CANT_READ_FILE_CODE);
write(fd,&toSend3, sizeof(toSend3));
printf("Cannot read <filename>\n");
closedir(dirPtr);
return(NULL);
}
numBytes=htonl(statBuffer.st_size);
write(fd, &numBytes, sizeof(numBytes));
printf("Sending %s, %d bytes\n",entryPtr >d_name,statBuffer.st_size);
while((numBytes=read(ab,buffer,BUFFER_LEN))>0)
{
printf("We read %d bytes\n", numBytes);
write(fd, buffer, numBytes);
}
//close the file and leave
close(ab);
break;
}
// if this is NULL it means we dind't send anything. we break the loop
// when a file to send it discovered.
if (entryPtr == NULL)
{
printf("No matching file\n");
int toSend2 = htonl(NO_MATCH_CODE);
write(fd, &toSend2, sizeof(toSend2));
}
// III. Finished:
closedir(dirPtr);
return(NULL);
}

correct way to use fwrite and fread

I wrote a program
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *fp;
int r;
char arr[] = "this is the string";
char str[20] = {'\0'};
fp = fopen("fwrite.txt", "w");
fwrite(arr, 1, sizeof(arr), fp);
fseek(fp, SEEK_SET, 0);
r = fread(str, 1, sizeof(arr), fp);
if(r == sizeof(arr))
printf("read successfully\n");
else
{
printf("read unsuccessfull\n");
exit(1);
}
printf("read = %d\n", r);
printf("%s\n", str);
fclose(fp);
return 0;
}
I am trying to read in this way but I am not able to do it. What is the problem here, is it that I should put &str[i] and run a loop for fread or will fread be able to put data in the str?
I am getting junk and I don't understand why?
The primary problem is that you have the arguments to fseek() backwards — you need the offset (0) before the whence (SEEK_SET). A secondary problem is that you attempt to read from a file open only for writing. A more minor issue in this context, but one that is generally very important, is that you don't error check the fopen() call. (It is relatively unlikely that this fopen() will fail, but funnier things have been known.) You should also check the fwrite() call (you already check the fread(), of course).
Fixing all these might lead to:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int rc = EXIT_SUCCESS;
int r;
const char file[] = "fwrite.txt";
char arr[] = "this is the string";
char str[20] = {'\0'};
FILE *fp = fopen(file, "w+b");
if (fp == 0)
{
fprintf(stderr, "Failed to open file %s for reading and writing\n", file);
rc = EXIT_FAILURE;
}
else
{
if (fwrite(arr, 1, sizeof(arr), fp) != sizeof(arr))
{
fprintf(stderr, "Failed to write to file %s\n", file);
rc = EXIT_FAILURE;
}
else
{
fseek(fp, 0, SEEK_SET);
r = fread(str, 1, sizeof(arr), fp);
if (r == sizeof(arr))
{
printf("read successful\n");
printf("read = %d bytes\n", r);
printf("read data [%s]\n", str);
}
else
{
printf("read unsuccessful\n");
rc = EXIT_FAILURE;
}
}
fclose(fp);
}
return rc;
}
Example run:
$ ./fi37
read successful
read = 19 bytes
read data [this is the string]
$
Note that this works in part because you write the null byte at the end of the output string to the file, and then read that back in. The file isn't really a text file if it contains null bytes. The b in "w+b" mode isn't really needed on Unix systems where there's no distinction between a binary and a text file. If you're writing null bytes to a file on Windows, you should use the b to indicate binary mode.
If you chose to, you could reduce the 'bushiness' (or depth of nesting) by not having a single return in the main() function. You could use return EXIT_FAILURE; and avoid an else and another set of braces. The code shown is careful to close the file if it was opened. In a general-purpose function, that's important. In main(), it is less critical since the exiting process will flush and close open files anyway.
You can't read in a file with the "w" mode for fopen, use "w+" instead.
"r" - Opens a file for reading. The file must exist.
"w" - Creates an empty file for writing. If a file with the same name already
exists, its content is erased and the file is considered as a new empty file.
"a" - Appends to a file. Writing operations, append data at the end of the
file. The file is created if it does not exist.
"r+" - Opens a file to update both reading and writing. The file must exist.
"w+" - Creates an empty file for both reading and writing.
"a+" - Opens a file for reading and appending.

Break a file into chunks and send it as binary from client to server in C using winsock?

I created an application that send a text file from client to server
So far i'm send it as string like this:
fp = fopen(filename, "r");
if (fp != NULL) {
newLen = fread(source, sizeof(char), 5000, fp);
if (newLen == 0) {
fputs("Error reading file", stderr);
} else {
source[++newLen] = '\0'; /* Just to be safe. */
}
}else{
printf("The file %s does not exist :(");
return 1;
}
fclose(fp);
send(s , source , strlen(source) , 0); //send file
However my professor told me I must send the file in Binary and be ready to accept a file of any size
I'm trying to figure out how to send the file in binary and break it into chunks
You can copy it one byte at a time.
Reading/writing more than a byte at a time theoretically would make it read and write more efficiently to disk. But since the binary is likely short, and disk I/O is already internally buffered it probably doesn't make a noticeable difference.
perror() is a convenient function that displays the text associated with an error code returned from the most recent UNIX system call. The text in the quotes is the title it displays before showing you the system message associated with the code.
exit(EXIT_FAILURE) exits with a -1 value which is what scripts can test to see if your program succeeded or failed, as the exit status can be retrieved for a UNIX program.
size_t is an integer type, but it's named size_t to give a hint as to what you're using it for.
If you wanted to transfer more data at a time you could. But 1-byte xfers is simple and safe and it works.
FILE *exein, *exeout;
exein = fopen("filein.exe", "rb");
if (exein == NULL) {
/* handle error */
perror("file open for reading");
exit(EXIT_FAILURE);
}
exeout = fopen("fileout.exe", "wb");
if (exeout == NULL) {
/* handle error */
perror("file open for writing");
exit(EXIT_FAILURE);
}
size_t n, m;
unsigned char buff[8192];
do {
n = fread(buff, 1, sizeof buff, exein);
if (n)
m = fwrite(buff, 1, n, exeout);
else
m = 0;
} while ((n > 0) && (n == m));
if (m)
perror("copy");

Missing Bytes in Client Server application in C

I have created a Client/Server application in C by using the SSL library. the issue i am facing is each time i send a file there are some bytes missing in the start of file.
let suppose the text file which i am sending contains
123456789
and when the client receive the file it would contains
56789
Server-Code
void sendFile(SSL* ssl)
{
char response[2048] = {0};
int read = 0;
FILE* fd;
fd = fopen("snt.txt","rb");
if (fd == NULL)
{
printf("file loading failed\n");
return;
}
while ((read=fread(response,sizeof(char),1024,fd)) > 0)
{
SSL_write(ssl,response,read);
printf("read :%d\n",read);
//puts(response);
//printf("***Data Sent***\n");
memset(response,0,1024);
}
printf("***Data Sent***\n");
fclose(fd);
}
Client Code
FILE *ft;
char filebuf[2048];
int read = 0;
int error_check=0;
ft = fopen("rcv.txt","ab");
if (ft == NULL)
{
printf("Can not open file to write\n");
return -1;
}
memset(filebuf,0,2048);
int cnk=1;
while ((error_check=BIO_read(bio,&read,sizeof(int)))>0)
{
//printf("%d read\n",read);
if (error_check==0)
break;
if (read==0)
break;
BIO_read(bio,filebuf,read);
printf("%d Chunk Recieved\n",cnk++);
//puts(filebuf);
fwrite(filebuf,sizeof(char),strlen(filebuf),ft);
memset(filebuf,0,2048);
}
printf("***File Recieved***");
fclose(ft);
the other issue is client side is not terminated, control doesn't get away from the while-loop, kindly guide me how can i tackle these issues
Assuming size(int) is 4, I'd say the 1st 4 bytes are read by this line:
while ((error_check=BIO_read(bio,&read,sizeof(int)))>0)
That leaves the rest of the data sent to this line:
BIO_read(bio,filebuf,read);
The latter reads it into filebuf which then is written to the file rcv.txt.

Resources