I am trying to stream files from the client to the server, but there is a incompatible data type from FILE to char, so everytime i run the client it gives me a segmentation error. I dont know how to get around this. Attached is the code for the server and client and below the problem with the client. i am trying to read file from client to buffer send it to server and server will read file from buffer and write it to a file.
client side http://pastebin.com/QtLbMgP3
server side http://pastebin.com/8PNchBUZ
// n = write(sock,"send me your message",18);
printf("Please enter the message: ");
bzero(buffer,256);
fgets(buffer,255,stdin);
ptr_myfile=fopen("test2.txt","w");
for(counter=1;counter <=10;counter++){
fwrite(&ptr_myfile,sizeof(*buffer),1,buffer);
n = read(sockfd,buffer,255);
n = write(sockfd,buffer,18);
n = write(sockfd,buffer,strlen(buffer));
if (n < 0) error("ERROR writing to socket");
bzero(buffer,256);
n = read(sockfd,buffer,255);
if (n < 0) error("ERROR reading from socket");
// printf("%s\n",buffer);
};//close for loop
close(sockfd);
}// close event loop
return 0;
}// close main function
Without going through all your code, the read, write, close series of APIs (NOT fopen, fread, etc) have an integer descriptor, not a FILE*.
You can't mix FILE* with int.
Looking at this line here:
fwrite(&ptr_myfile,sizeof(*buffer),1,buffer);
How does that even compile?
This is likely correct:
fwrite(buffer, 1, sizeof(buffer), ptr_myfile );
The above line will read up to 256 bytes (the size of your buffer array) from the file and copy the data into buffer. Notice that I'm passing ptr_myfile, not &ptr_myfile.
Check your fwrite statement, are you trying to write into the file, or read from the file into the buffer?
If it is the previous case, then use fwrite(buffer, sizeof(buffer),1, ptr_myfile) i.e. the stream to which you are writing to is the last variable.
If the case is latter then you will first need to read from the stream using fgets or getchar or some function like that before you actually put it into the buffer.
Hope it helps!
Okay, to read a file at the client and send it to server,
fp=fopen("<filename>", "r");
//This opens the file and initializes the pointer fp to the start of the file Start of
//the file, not its text necessarily
Now you could use fgetc() function [Character by character] or fgets() function [In case the text is formatted, you can read the entire line into the buffer] to read from your file into the buffer.
fgets(buffer,sizeof(buffer),fp);
//This could be ambiguous as the second argument should correspond to
//pre-known limit of bytes to read here some Macro maybe.
Now, simple use send() to dispatch this buffer to server.
On the server side, receive the input data from network into some 'buffer' using recv() and use fputs or fprintf or any convenient function to write into the file opened there in Write mode.
Related
I am trying to send a file and its name through a socket in C.
The relevant server code is:
char file[18];
memset(file, 0, 18);
file[17] = '\0';
int recvd = recv(newsock, file, 16, 0);
char local_file_path[200];
memset(local_file_path, 0, 200);
if(recvd == -1 || recv == 0) {
fprintf(stderr, "File name not received");
continue;
}
strcat(local_file_path, "/home/ubuntu/results/");
strcat(local_file_path, file);
FILE* fp = fopen(local_file_path, "wb");
char buffer[4096];
while(1)
{
recvd = recv(newsock, buffer, 4096, 0);
fwrite(buffer, sizeof(char), recvd, fp);
if(recvd == -1 || recvd == 0) {
fclose(fp);
break;
}
}
close(newsock);
}
close(servSock);
The relevant client code is:
char* my_16_long_fname = "filename1234.txt"
int ret = send(sock, my_16_long_file_fname, strlen(my_16_long_fname), 0)
This code, however, has been creating lots of undefined behaviour such as:
1.Receiving garbage filenames filled with garbage
2.Receiving empty files (so a name with nothing inside - could be some other bug but possibly due to this)
I have thought about a few solutions:
1.Diferentiate file types by signature/header and generate a file name on the server side. Besides this being a cheap solution which doesn't teach me how to actually solve the problem, it doesn't work with the logic i'm using, where sometimes I send error codes instead of file names after opening the socket.
2.Iterate over the recv'd buffer on the first call to recv until I encounter a '\0' character. Then write the remainder of the buffer as binary data and keep on receiving data as usual.
Is this the most efficient/simplest and solid solution to this issue, which will prevent any undefined behaviour?
There is no way your current code could possibly work. If the filename is always one character, your code can read too many characters. If your filename is always the same number of characters but more than one character, your code can read too few characters. If the filename is a variable number of characters, your code could read a smaller number than was sent.
So there is no sending protocol for which this could be valid receiving code.
Until you are an expert on writing networking code, always follow these two steps:
Document the protocol.
How many bytes does the filename occupy? Is it a fixed number or a variable number? Is it always followed by a zero byte?
Implement the protocol.
For example, your code reads up to 16 bytes for the filename. But it never checks if it received the whole file name. What if it only received a single byte?
I'm facing a problem to store a file coming from the standard input into a buffer.
Here is my code :
//Go to the end of stdin and calculate the number of elements
int num;
fseek (stdin, 0, SEEK_END);
num = ftell (stdin);
//If there is a file in the standard input
if(num > 0) {
int resRead;
//Read the file and store it into buffer
if((resRead = read(STDIN_FILENO,buffer,num))){
fprintf(stderr, "Error: Could not store the input into buffer\n");
}
//Display the buffer
for (int i = 0; i < num; ++i)
{
printf("%c\n",buffer[i]);
}
}
When i launch my code : ./interpreter < file.txt, i don't get the content of the buffer.
I've to precise that my file has content and when i check the value of num it correspond exactly to the number of char in the file.
Any ideas ? :)
Thank you !!
Operating system level streaming or indirection of a file to a binary does not work in this scenario unless you have file reading code from standard input in your program.
Better option is keep the file in directory and pass the file location as parameter to your program. And use fopen() to read the file.
stdin is a stream, which means that it doesn't have an "end" that you can seek to. There's no way to know if it received a redirected file or if it's reading user input from the console.
You need to dynamically allocate space for your buffer using malloc and read in up to as many bytes as you can fit. If there's still more data, use realloc to expand the buffer (a good strategy is to double the size each time) and read more.
If you know you'll always be reading from a file, you should change the program to take the file name from the command line and use fopen to open the file.
I see a plenty of examples but none addresses what I want to accomplish. I need to read the bytes from a socket and write them in to a file. In this Code Project blog I see where in the client script a while loop iterates through a read call:
while((n = read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0)
So I modified the code do that fputs(recvBuff, f1) where f1 is a pointer to a pdf file. A pdf file is also a file I'm fetching from the server so I need to reassemble it, however the fputs operated with a string and corrupts the file, so I need a byte "writer" so fwrite would have been the choice but I can't get fwrite to work. I ended up modifying my code to resemble some of the examples to test it out but to no avail.
If in fwrite the first parameters is the 'data' how would I pass it? I've tried the read() call as in the while loop above but that seem to return an integer rather then a byte stream. Any ideas?
I'm new to programming but am new to C and would appreciate a little push in a right direction. Thanks.
You want something more like this. fwrite doesn't return a stream it returns the number of items (i.e. the 3rd parameter) successfully written. In this case the "item" is a single char and you are attempting to write "bytesRead" number of them. Good form dictates that you should check that the result fread returns is the same as you requested be written but this rarely fails on a disk file so many people skip it in non-critical situations. You may want to add that on yourself.
FILE *f1;
int sockfd;
char recvBuff[4096];
size_t bytesWritten;
ssize_t bytesRead;
while((bytesRead = read(sockfd, recvBuff, sizeof(recvBuff))) > 0)
bytesWritten = fwrite(recvBuff, 1, bytesRead, f1);
I'm currently still programming a simple client-server application in C via Ubuntu. So far my login function seems to have worked well (enter some text in client, grab text from a file in server and verify), but this particular display option is giving me trouble.
Some snippets of the server-side code (I grabbed the file copy to buffer function below from another site):
char bflag[1]; //mainmenu option recveived from client
char buffer[BUFSIZE+1]; //BUFSIZE is 1024
long lSize;
size_t result;
FILE * userf;
userf = fopen("Books.txt", "r+b");
recv(new_sockfd, bflag, BUFSIZE, 0); //receive flag from clientside
if ( (strncmp (bflag, "a", 1)) == 0) //display flag received
{
fseek (userf , 0 , SEEK_END);
lSize = ftell (userf);
rewind (userf);
// copy the file into the buffer:
result = fread (buffer,1,lSize,userf);
send(new_sockfd, buffer, BUFSIZE, 0);
}
fclose(userf);
And on the client side, utilizing a switch for the various options:
char bbuf[BUFSIZE+1]; //BUFSIZE is 1024
switch (mmenuc)
{
case 1:
{
strcpy (mmenuf, "a");
send (sockfd, mmenuf, BUFSIZE,0);//send flag 'a' to server
system("clear");
printf("Listing of books available:\n");
printf("O = Available X = Unavailable\n");
printf("\n");
recv (sockfd, bbuf, BUFSIZE,0);
printf ("%s", bbuf);
printf("\n");
getchar(); //eats the "\n"
getchar(); //to pause
break;
}
The problem that I am facing now is that the all the text in the file is retrieved and appears on the client side terminal fine, but on the server side terminal it gives a Segmentation Fault.
I assume there's a buffer overflow somewhere, but I'm not sure what's causing it.
Also, the Books.txt file is padded with spaces for an editing function later.
The server probably stores something like "a< cr >< lf >" in the buffer "Bflag". Not good. Should cause an error, but does not always cause one immediately.
You do not need to figure out the size of your file before you do the read:
Just issue: result = fread (buffer,1,BUFSIZE,userf);
Now, if your file ends up being larger than the buffer, your program won't crash but just not read all the file. You can change your working program later on to handle the case that the file is larger than one buffer. Use "result" (if it is larger than zero) for the number of bytes-to-write to the client.
If your file is (more than a few bytes) larger than BUFSIZE, it will probably cause a "segmentation fault" on exit of the function you provided in the first codeblock. I think that's where your segmentation fault comes from.
I have written a program in c to send a file line by line to a server from a client in c. After the file is transmitted completely, I have provided a line endoffile in the txt file to string compare in the server to identify that the file is over and the next file is being transmitted next. The next file has to be written to another file in the server. But the problem is that the strcmp is never detecting the endoffile in the code and endoffile recieved from the file in client as equal strings amd continues to write the next file from the client to the same file in server.
char enof[]="endoffile";
...
do
{
rewind(appcrt);
bytes_recieved = recv(pass_arg.connected, recv_data_c, strlen(recv_data_c), 0);
recv_data_c[bytes_recieved-1] = '\0';
fputs(recv_data_c, appcrt);
if(strcmp(enof,recv_data_c) == 0){break;}
}while(check<count);
The text file:
Necessary data
that is
being transmitted
to be written to the file
endoffile
The code used for reading from the txt file and sending to the server:
while (fgets(line, sizeof(line), crt) != NULL)
{
send(sock, line, sizeof(line), 0);
}
What change I have to make in the condition so that the problem is resolved and the code exits from the do....while(); loop. Thanks in advance.
Operating platform: Linux
Edit1: Edited the do....while() as follows:
do
{
rewind(appcrt);
bytes_recieved = recv(pass_arg.connected, recv_data_c, 100, 0);
recv_data_c[bytes_recieved] = '\0';
fputs(recv_data_c, appcrt);
printf("%s-%s",enof,recv_data_c);
//if(strcmp(enof,recv_data_c) == 0){break;}
}while(check<count);
Got the following output in terminal:
endoffile-file1line1
endoffile-file1line2
endoffile-file1line3
endoffile-file1line4
endoffile-file1line5
endoffile-file1line6
endoffile-endoffile
endoffile-file2line1
endoffile-file2line2
endoffile-file2line3
endoffile-file2line4
endoffile-file2line5
endoffile-file2line6
.
.
.
Still no hope.
Even though the client is writing a line at a time to the socket this is not how the server will consume it as data transferred over a socket is just a stream of bytes. The server must read up to the next new line character and then compare. A simple algorithm would read a byte at a time and check if it is the newline character and if is not then append it to a string until a newline character is read:
/* Read next line. */
memset(line, 0, sizeof(line));
size_t line_len = 0;
while (line_len < sizeof(line) - 1 &&
1 == recv(pass_arg.connected, &line[line_len], 1, 0))
{
if ('\n' == line[line_len]) break;
line_len++;
}
Apart from that, there are several problems with the code:
you need to send what was read from the file as it may be less than the sizeof(line). Change:
send(sock, line, sizeof(line), 0);
to:
send(sock, line, strlen(line), 0);
and also check the return value of send() to determine if it was successful.
the following is incorrect as it would only read at a maximum what was previously read (or if was initialised to an empty string nothing would be read):
bytes_recieved = recv(pass_arg.connected,
recv_data_c, strlen(recv_data_c), 0);
and, again, check the return value especially as the return value is being used to index an array. If recv() fails it returns -1, which will result in out of bounds access on the array causing undefined behaviour.
while (fgets(line, sizeof(line), crt) != NULL)
{
send(sock, line, sizeof(line), 0);
}
Don't forget that fgets() may only read one byte, if the line is blank. Thus your send() call is sending a lot of uninitialized data every call -- either contents of previous lines or random memory free()d by your application earlier.
Thus, your receiving program would need to compare against:
endoffiletten to the file
to finally see the final string. (Assuming that the line buffer started out full of ASCII NUL characters.)