Transfering files in a client-server socket connection properly - c

I have written the following code for sending file from a client:
FILE *fp = fopen("video.mp4","rb");
if(fp==NULL)
{
printf("File opern error");
return 1;
}
int bytesToWrite=84440670;
int bytesWritten=0;
while(bytesWritten<bytesToWrite)
{
int m=minimum(256,bytesToWrite-bytesWritten);
/* First read file in chunks of 256 bytes or the remaining bytes*/
unsigned char *buff=malloc(sizeof(char)*m);
bzero(buff, m);
int nread = fread(buff,1,m,fp);
printf("Bytes read %d \n", nread);
bytesWritten+=m;
/* If read was success, send data. */
if(nread > 0)
{
printf("Sending \n");
write(sockfd, buff, nread);
}
/*
* There is something tricky going on with read ..
* Either there was error, or we reached end of file.
*/
if (nread < 256)
{
if (feof(fp))
printf("End of file\n");
if (ferror(fp))
printf("Error reading\n");
break;
}
}
and the following code for receiving by the server :
FILE *fp;
fp = fopen("receive.mp4", "wb");
if(NULL == fp)
{
printf("Error opening file");
return 1;
}
int bytesToRead=84440670;
/* Receive data in chunks of 256 or remaining bytes */
int totalbytesread=0;
while(totalbytesread < bytesToRead)
{
int m = minimum(256,bytesToRead-totalbytesread);
char *recvBuff=malloc(sizeof(char)*m);
bzero(recvBuff,m);
bytesReceived = read(newsocfd, recvBuff,m );
printf("Bytes received %d\n",bytesReceived);
totalbytesread += bytesReceived;
fwrite(recvBuff, 1,bytesReceived,fp);
}
if(bytesReceived < 0)
{
printf("\n Read Error \n");
}
The sending is working correctly for .txt files ,some data is being lost in sending other formats(for e.g some ending seconds of .mp4 files is not being sent).
I am new to socket programming. Any help would be deeply appreciated.

You are missing a fclose(fp); in the server after you have finished receiving. You can also use fflush(fp); to just flush the contents.
Besides, there are several memory leaks and improper error handling.

Related

Fail to read/write struct to fifo recursively in C

In an exercise problem, I am required to build a client program (write first) that opens a .txt file, put each line and the total bytes of each line into a struct variable and then send it out to the server program (read first). Right after this is done, the client program will also receive a struct file (similarly only has char * and int attributes) from the server program.
// Below are global variables in both programs
#define BUFSIZE 1024
struct info_pack
{
char line[BUFSIZE]; // the line to receive messages
int bytes; // the bytes of data transferred
};
char fifo_path[] = "./my_fifo";
struct info_pack info_w; // the info_pack for writing each line in text.txt
struct info_pack info_r; // the info_pack for reading feedback info_pack sent from the server program
First is the client program:
// the main() in the client program
int main()
{
int fd;
int i = 0, index = 1, bytes = 0, line_length, fifo_read;
char *file_path = "/home/text.txt";
FILE *fd2;
mkfifo(fifo_path, 0666);
if ((fd2 = fopen(file_path, "r")) < 0)
{
perror("Opening file");
return -1;
}
else
{
printf("Successfully open the target file\n");
while (fgets(info.line, BUFSIZE, fd2) != NULL)
// the "segmentation fault" error appears right after this line
{
info_w.bytes = strlen(line);
fd = open(fifo_path, O_WRONLY);
printf("The %d th line sent out is: %s\n%d bytes are sent\n\n",
index, info_w.line, info_w.bytes);
write(fd, &info_w, sizeof(info_w) + 1);
close(fd);
fd = open(fifo_path, O_RDONLY);
fifo_read = read(fd, &info_r, sizeof(info_r));
close(fd);
if (fifo_read > 0)
{
printf("Feedback: %s\nand %d bytes are returned\n", info_r.line, info_r.bytes);
}
}
printf("All data is successfully transfered\n");
}
return 0;
}
Then is the server program
// the main() in the server program
int main()
{
int fd, fifo_read;
int line_length;
char *feedback = "SUCCESS";
strcpy(info_w.line, feedback);
info_w.bytes = strlen(feedback);
// define a constant info_pack variable to send to the client program
if (mkfifo(fifo_path, 0666) < 0)
{
perror("client end: ");
exit(-1);
}
while (1)
// This server program will wait for any one single client's message
// This server program can only be terminated by manually input signals (like ^\)
{
fd = open(fifo_path, O_RDONLY);
printf("waiting for client's message\n");
fifo_read = read(fd, &info_r, sizeof(info_r));
close(fd);
if (fifo_read > 0)
// if receive the struct variable, print all of its attributes
{
if (info_r == NULL)
printf("Found no lines sent from the client\n");
else
printf("Read from fifo:\n %s\n(in info)%d bytes read (actually)%d bytes read\n", info_r.line, info_r.bytes, fifo_read);
}
else
{
sleep(1);
printf("Fail to read data from the client\n");
}
// Because of the error in client program this server program
// always pause here
fd = open(fifo_path, O_WRONLY);
printf("Now writing feedback to the client\n");
write(fd, info_w, sizeof(info_w));
close(fd);
}
}
Could anyone explain why the segmentation fault error appears in the client program? Then I can test if the both the client and the server can co-op properly.By the way, I read this post already but, in this post, it is a one-time data stream and I cannot find any hints in it.

Can not use socket after file transfer - C Socket

In here I am sending file name first then sending the file in chunks, then trying to read the received message but it is just freezing. No respond. But after loop if I shutdown the WR shutdown(connfd,SHUT_WR); It is working fine. Though I should be able to send message again, if I do this I can not do that.
CLIENT.C
write(sockfd, fname,100);
FILE *fp = fopen(fname,"rb");
if(fp==NULL)
{
printf("File opern error");
exit(1);
}
int hi = 0;
while(1)
{
/* First read file in chunks of 256 bytes */
unsigned char buff[1024]={0};
int nread = fread(buff,1,1024,fp);
/* If read was success, send data. */
if(nread > 0)
{
hi++;
//printf("Sending \n");
write(sockfd, buff, nread);
}
if (nread < 1024)
{
if (feof(fp))
{
printf("File transfer completed!\n");
}
if (ferror(fp))
printf("Error reading\n");
break;
}
}
char fname2[100];
// cant read
read(sockfd, fname2, 100);
printf("File Name: %s\n",fname2);
SERVER.C
FILE *fp;
int bytesReceived = 0;
char recvBuff[1024];
char fname[100];
char fname2[100];
read(newsockfd, fname, 100);
//strcat(fname,"AK");
printf("File Name: %s\n",fname);
printf("Receiving file...");
fp = fopen(fname, "ab");
if(NULL == fp)
{
printf("Error opening file");
}
long double sz=1;
/* Receive data in chunks of 256 bytes */
printf("\nCompleted.\n");
int hi = 0;
while((bytesReceived = read(newsockfd, recvBuff, 1024)) > 0)
{
hi++;
sz++;
fwrite(recvBuff, 1,bytesReceived,fp);
}
printf("Not pring this this!");
if(bytesReceived < 0)
{
printf("\n Read Error \n");
}
write(newsockfd, "SayGee",100);
I had to send the size of the file, then check from the other side inside loop. It was in deadlock.I found the solution. So thanks anyway!

Program stuck writing contents to the file in C

I'm sending a file from the client to the server.
Client sends filename
Server receives filename
Client sends file size
Server receives file size
Client sends file contents
Server receives file contents
When I print out the file size that I sent, it is the exact number of bytes as the file I wish to send so that's fine. The issue is that the server (receives) doesn't seem to exit the while loop when writing to the new file. I know this because the final print statement printf("The server has received the requested document\n"); is never reached and it just hangs. What could be causing this?
Client snippet (sends):
else if(strcmp(shortCommand, "put") == 0){
char *tmp = buf + 4;
char filename[MAX_BLOCK_SIZE];
size_t size, bytes_read, bytes_written;
int x;
strcpy(filename, "filename ");
strcat(filename, tmp);
FILE *fp;
printf("File name: %s\n", tmp);
fp = fopen(tmp, "rb");
if(fp == NULL){
printf("ERROR: Requested file does not exist.\n");
}
else{
printf("Client sending filename...\n");
if ((x = write(sd, buf, sizeof(buf))) < 0){ //sending the file name to the client first
printf("Error sending client's filename.\n");
}
printf("Client sending file...\n");
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fseek(fp, 0, SEEK_SET);
printf("Sending file size\n");
if((write(sd, &size, sizeof(size))) < 0){ //sending filesize
printf("error sending file size\n");
}
printf("Sending file\n");
while((bytes_read = fread(buf, 1, sizeof(buf), fp)) > 0){ //sending file contents
if ((bytes_written = write(sd, buf, bytes_read)) < 0){
printf("Error sending client file.\n");
}
}
printf("bytes written: %ld\n", bytes_written);
fclose(fp);
}
}
Server snippet (receives):
if(strcmp(shortCommand, "put") == 0){
char *tmp = buf + 4;
char filename2[MAX_BLOCK_SIZE];
size_t filesize;
size_t total_bytes_read = 0;
ssize_t bytes_read = 0;
size_t error;
FILE *fp;
strcpy(filename2, tmp);
printf("Server receiving file name...\n"); //filename is received on the first read before this IF
fp = fopen(filename2, "wb");
if(fp == NULL){
printf("File could not be opened.\n");
exit(1);
}
printf("Server receiving file size...\n");
if((error = read(sd, &filesize, sizeof(filesize))) < 0){ //receiving file size
perror("Error reading filesize\n");
exit(1);
}
printf("Filesize is: %ld \n", filesize);
while(total_bytes_read < filesize){
while((bytes_read = read(sd, buf, sizeof(buf))) > 0){ //receving file contents and writing to file
fwrite(buf, 1, bytes_read, fp);
total_bytes_read += bytes_read;
if(ferror(fp)){
perror("error");
fclose(fp);
}
}
}
printf("The server has received the requested document.\n");
fflush(stdout);
fclose(fp);
}
After I exit the program by force, I can actually see that the file has been copied. Just doesn't exit that while loop to let me go back to the client.
Time for some basic debugging. I'd suggest changing your read loop to something like this:
while (total_bytes_read < filesize) {
printf("DEBUG A: total=%zu, size=%zu\n", total_bytes_read, filesize);
while ((bytes_read = read(sd, buf, sizeof(buf))) > 0) {
printf("DEBUG B: read=%zd\n", bytes_read);
fwrite(buf, 1, bytes_read, fp);
total_bytes_read += bytes_read;
printf("DEBUG C: total=%zu\n", total_bytes_read);
if (ferror(fp))
printf("DEBUG D\n");
perror("error");
fclose(fp);
}
printf("DEBUG E\n");
}
printf("DEBUG F\n");
}
printf("DEBUG G\n");
Then run it, piping the output through less or some other pager, it should then hopefully become clearer what's actually happening.
Feel free to post the output of this modified code (in a comment, or in the actual question), we'll no doubt be able to help with the analysis.

File transfer from client to server

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;
}
}

File partially sent in c

I'm trying to send files using TCP from a windows client to a Linux server in C.
The size of the buffer I use to send the data is 65535. When the size of the file exceeds this value, I get an error saying 'connection reset by peer' or the error code 10054. When the size of the file is less than 65535 bytes, the server receives only a part of it (usually 2760 bytes).
I just want to send files with a maximum size of 50 MB.
This is the part of the windows client that I use to send data:
char *fileName; // pointer to filename
char buf[65535]; // buffer
int fileSize; // # bytes to send
for(i = 0; i < ARRAYSIZE; i++) {
if(selectList[i] != NULL) {
// select file
fileName= selectList[i]; // get path and filename from selectList
printf("=============================================\nSending: %s\n", fileName);
filefd = fopen(fileName, "rb"); // open file
if(filefd == NULL) {
printf("File %s not found\n", fileName);
exit(1);
}
// read and send file
memset(buf, '\0', 65535);
while((fileSize= fread(buf, sizeof(char), 65535, filefd)) > 0) { // read file
if((numberOfBytes = send(sockfd, buf, fileSize, 0)) < 0) { // send buffer
printf("send: %s (Error: %d)\n", filename, WSAGetLastError());
break;
}
printf("#bytes = %i \n", numberOfBytes);
memset(buf, '\0', 65535);
}
printf("File %s send!\n", filename);
// close file after sending it
if(fclose(filefd) < 0) {
printf("fclose: %i", WSAGetLastError());
}
} else if(selectList[0] == NULL) {
printf("no files selected");
}
}
The selectList contains multiple strings such as: C:\Windows\test.txt
The recieve part of the Linux server:
char* fr_name = "/home/MtFS/UploadedFiles/public/testFile.gif";
FILE *fr = fopen(fr_name, "wb");
if(fr == NULL)
printf("[Open_File]file %s cannot be created\n", fr_name);
else {
bzero(revbuf, LENGTH);
int fr_block_sz = 0;
while((fr_block_sz = recv(nsockfd, revbuf, LENGTH, 0)) > 0) {
int write_sz = fwrite(revbuf, sizeof(char), fr_block_sz, fr);
if(write_sz < fr_block_sz) {
error("[Write] error\n");
}
bzero(revbuf, LENGTH);
if (fr_block_sz == 0 || fr_block_sz != 512) {
break;
}
}
if(fr_block_sz < 0) {
if (errno == EAGAIN) {
printf("[Receive] time out\n");
}
else {
printf("[Receive] error\n");
exit(1);
}
}
printf("[Receive] succesfull\n");
fclose(fr);
}
What am I doing wrong?
Your problem are those 3 lines of code. That's not the correct way to know that you're done:
if (fr_block_sz == 0 || fr_block_sz != 512) {
break;
}
Also you check against 512 instead of LENGTH. But only 0 means that you're done (assuming your connection is not NONBLOCKED.)
As a side note: you do not have to clear your buffers (bzero, memset) before using them with a read since the read/recv will overwrite the content of the buffers anyway.
I think the culprit is this line in your server
if (fr_block_sz == 0 || fr_block_sz != 512) {
fr_block_sz cab be anything between 1 to 65535 - the size block that you sent.
In your code, when its not 512 so your server is terminating the connection.

Resources