C: incomplete file transfer through TCP server and client sockets - c

I am having trouble transferring files through TCP sockets in C. I send the files in little chunks of 8192 bytes from a server to a client. The issue is that the client receives the one before last incompletely and does not receive the last one at all.
Here are both relevant parts of the code.
server:
fd = open(filename,O_RDONLY);
if (fd == -1)
{
fprintf(stderr, "Error opening file --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
/* Get file stats */
if (fstat(fd, &file_stat) < 0)
{
fprintf(stderr, "Error fstat --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
fprintf(stdout, "File Size: \n%d bytes\n", file_stat.st_size);
sprintf(file_size, "%d", file_stat.st_size);
/* Sending file size */
len = send(peer_socket, file_size, sizeof(file_size), 0);
if (len < 0)
{
fprintf(stderr, "Error on sending greetings --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
fprintf(stdout, "Server sent %d bytes for the size\n", len);
offset = 0;
remain_data = file_stat.st_size;
/* Sending file data */
while(((sent_bytes = sendfile(peer_socket, fd,&offset, BUFSIZ))>0)&&(remain_data > 0))
{
remain_data -= sent_bytes;
fprintf(stdout, "2. Server sent %d bytes from file's data, offset is now : %d and remaining data = %d\n", sent_bytes, offset, remain_data);
}
and client side:
ecv(client_socket, buffer, BUFSIZ, 0);
file_size = atoi(buffer);
fprintf(stdout, "\nFile size : %d\n", file_size);
//received_file = fclose(fopen(FILENAME, "w"));
received_file = fopen(FILENAME, "w");
if (received_file == NULL)
{
fprintf(stderr, "Failed to open file --> %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
remain_data = file_size;
while ((remain_data > 0)&&((len = recv(client_socket, buffer, BUFSIZ, 0)) > 0))
{
fwrite(buffer, sizeof(char), len, received_file);
remain_data -= len;
//if (remain_data < BUFSIZ)
// buffsize = remain_data;
//bzero(buffer,BUFSIZ);
//if (len == 0 || len != BUFSIZ)
// break;
fprintf(stdout, "Received %d bytes , %d bytes remaining\n", len, remain_data);
}
//code for accelerator here
fclose(received_file);
The output on server side looks like this (which seems to be correct):
But on the client side this is what I get:
From there the applications on both sides are stuck forever. Any idea what might cause the trouble?
Thanks for your answers

Related

[UNIX]Sending large file socket stream in c

I've created a Client in C that essentially sends the content of a file and a number of line to remove to the Server. The server creates a child that reads the content and then send it right back to the Client, except for the line received. The communication is made with a socket stream, and the content of the file is sent char-for-char. The problem appears when the client send a file bigger than 9.9Mb, the server reads the contents of the file but at some point it stops, and the only way for closing the server is by killing the process with CTRL-C.
This is the code of the child of the server:
if (fork() == 0){
close(listen_sd);
host = gethostbyaddr((char *)&client_addr.sin_addr, sizeof(client_addr.sin_addr), AF_INET);
if (host == NULL) {
printf("Server (figlio %d): client host non trovato.\n", getpid());
exit(8);
}
else
printf("Server (figlio %d): operazione richiesta da %s.\n", getpid(), host->h_name);
host = gethostbyaddr((char *)&client_addr.sin_addr, sizeof(client_addr.sin_addr), AF_INET);
if ((read(conn_sd, &sub_line, 1) > 0))
printf("Server (figlio %d): eliminazione della linea %d...\n", getpid(), sub_line);
line = 1;
while((nread = read(conn_sd, &c, sizeof(char))) != 0) {
if (nread < 0){
printf("Server (figlio %d): impossibile leggere il file.\n", getpid(), sub_line);
exit(EXIT_FAILURE);
}
if(line != sub_line)
write(conn_sd, &c, 1);
if(c == '\n')
line += 1;
}
close(conn_sd);
exit(0);
}
And this is the code of the client that sends the content of the file, reads the result and then write it on a file:
#define DIM_BUFF 256
[...]
write(sd, &line, sizeof(int));
char buff[DIM_BUFF];
while ((nread = read(fd_sorg, buff, DIM_BUFF)) > 0)
write(sd, buff, nread);
shutdown(sd, 1);
while ((nread = read(sd, buff, DIM_BUFF)) > 0){
write(fd_dest, buff, nread);
}

Client reading more bytes than was sent in C - linux

EDIT: Im trying to send a file from the server to the client. When I send a file of 44 bytes, the client reads in 256 bytes on the first iteration (which is the size of char array buf) and on the next iteration reads the remaining 44 bytes. Why does it not read the 44 bytes initially?
Client snippet ( receives file ):
while((bytes_read = read(sd, buf, sizeof(buf))) > 0){ //receving file contents and writing to file
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)){
perror("Error when writing to file\n");
exit(1);
fclose(fp);
}
//printf("Filesize is: %zu \n", filesize);
if(total_bytes_read == filesize){
break;
}
}
printf("The client has received the file\n");
}
server part(sends file):
strcpy(buf, "no issues");
if((y = write(sd, buf, sizeof(buf))) < 0){
perror("Error reporting back to client\n");
}
fseek(fp, 0, SEEK_END);
filesize = ftell(fp);
fseek(fp, 0, SEEK_SET);
printf("Sending file size\n");
if((write(sd, &filesize, sizeof(filesize))) < 0){ //sending filesize
printf("error sending file size\n");
}
printf("Filesize is: %zu \n", filesize);
printf("Sending file\n");
while((bytes_read = fread(buf, 1, sizeof(buf), fp)) > 0){ //sending file contents
printf("DEBUG A: Bytes read %zu \n", bytes_read);
if ((bytes_written = write(sd, buf, bytes_read)) < 0){
printf("Error sending server file.\n");
}
printf("DEBUG B: Bytes sent %zu \n", bytes_written);
total_bytes_sent += bytes_written;
printf("Total bytes sent %zi \n", total_bytes_sent);
}
printf("File has been sent\n");
fclose(fp);
}
If more code is required I will post it, let me know. Greatly appreciate any help!

c - client server socket programming - sending files

I am having trouble sending and receiving files while working with sockets in C.
Let's say I have a file that is 2,463 bytes big and I want to send it from client to server but it never sends the entire file.
I've been searching the internet for a while now but couldn't find a solution so I'd be very glad if someone could tell me how to make this work.
Here is my code:
Client:
char buffer[256];
bzero(buffer, 256);
int block_size;
while(1){
block_size = fread(buffer, sizeof(char), sizeof(buffer), fs); // read from the file
if (block_size == 0){
break;
}
if (block_size < 0){
perror("ERROR: Failed while sending data.");
exit(EXIT_FAILURE);
break;
}
void *p = buffer;
while (block_size > 0) {
int bytes_written = write(clientSocket, buffer, block_size); // send the data to server
if (bytes_written <= 0) {
perror("ERROR: Failed while sending data.");
exit(EXIT_FAILURE);
}
block_size -= bytes_written;
p += bytes_written;
}
bzero(buffer, 256);
}
Server:
bzero(buffer, 256);
int file_block_size = 0;
while (1){
bzero(buffer, 256);
file_block_size = read(incoming_socket, buffer,255); // read the data from client
fwrite(buffer, sizeof(char), file_block_size, fr); // write the data to file
if (file_block_size == 0 || file_block_size < 256){
fwrite(buffer, sizeof(char), file_block_size, fr);
break;
}
}
As I've said, this never sends the entire file that is for example 2,463 bytes big, only a portion of it.
Thanks in advance, will be glad for any help I can get.
You need to pair your read with a write. As in the current state your client code will send only the result of your last read operation since you are overwriting the contents of your buffer on each read.
Try something like this on the client side:
char buffer[256];
size_t bytes_read = 0;
ssize_t bytes_written = 0;
do{
bytes_read = fread(buffer, sizeof(char), sizeof(buffer), fs);
if(ferror(fs))
{
perror("Error while reading from file.");
close(clientSocket);
fclose(fs);
exit(EXIT_FAILURE);
}
bytes_written = write(clientSocket, buffer, bytes_read);
printf("Write operation status: %s; bytes sent: %d\n", strerror(errno), bytes_written);
} while(!feof(fs) && bytes_written != -1);
And on the server side I would do:
char buffer[256];
ssize_t bytes_read = 0;
while((bytes_read = read(incoming_socket, buffer, sizeof(buffer))) > 0)
{
printf("%d bytes read\n", bytes_read);
fwrite(buffer, sizeof(char), bytes_read, fr);
if(ferror(fr))
{
perror("Error while writing to file");
close(incoming_socket);
fclose(fr);
exit(EXIT_FAILURE);
}
}
if(bytes_read == -1)
printf("%s\n", strerror(errno));

C socket, send message after file, TCP

I want to send file through socket and after that i want to send three messages. This code below works, but i have to send first sentence two times. My question is why? Without one sentence1, receiver display sentence2, sentence3 and sentence3. What is wrong with this code?
I'm using tcp protocol.
Sender.c
char file_size[256];
struct stat file_stat;
int sent_bytes = 0;
int fd;
int offset;
int remain_data;
fd = open(FILE_TO_SEND, O_RDONLY);
if (fd == -1)
{
fprintf(stderr, "Error opening file --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
/* Get file stats */
if (fstat(fd, &file_stat) < 0)
{
fprintf(stderr, "Error fstat --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
fprintf(stdout, "File Size: \n%d bytes\n", file_stat.st_size);
sprintf(file_size, "%d", file_stat.st_size);
write(sck, file_size, 256);
char buffer[1024] = "";
while (1) {
int bytes_read = read(fd, buffer, sizeof(buffer));
if (bytes_read == 0)
break;
void *p = buffer;
while (bytes_read > 0) {
int bytes_written = write(sck, p, bytes_read);
if (bytes_written <= 0) {
// handle errors
}
bytes_read -= bytes_written;
p += bytes_written;
}
}
char sentence[1024];
write(sck, sentence1, 1024);
write(sck, sentence1, 1024);
write(sck, sentence2, 1024);
write(sck, sentence3, 1024);
Receiver.c
char buffer[1024] = "";
int sck = *((int*) arg);
int file_size;
read(sck, buffer, 256);
file_size = atoi(buffer);
ssize_t len;
FILE *received_file;
int remain_data = 0;
received_file = fopen("plik.pdf", "w");
if (received_file == NULL)
{
fprintf(stderr, "Failed to open file foo --> %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
remain_data = file_size;
while (((len = recv(sck, buffer, 1024, 0)) > 0) && (remain_data > 0))
{
fwrite(buffer, sizeof(char), len, received_file);
remain_data -= len;
}
fclose(received_file);
read (sck, buffer, 1024);
printf("%s 1\n", buffer);
read (sck, buffer, 1024);
printf("%s 2\n", buffer);
read (sck, buffer, 1024);
printf("%s 3\n", buffer);
Nothing to do with TCP protocol. Your logic is flawed. You are receiving the data and then checking for remain_data. So your sentence1 is received and discarded in the while loop.
Move your recv() into the body of while to fix this or change the order in while.
while ((remain_data > 0) && ((len = recv(sck, buffer, 1024, 0)) > 0))
In the modified while, you call recv() only if remain_data > 0. recv() is not called if remain_data == 0 (lazy evaluation). So your while loop ends immediately after receiving the file and ready to receive your sentences. In your code, the while loop read the first sentence, then checked remain_data > 0 effectively discarding sentence1

Client prints Half Data Before Connection is Closed By Server on Socket

I have this scenario. I'm trying to use socket in C to send and receive data. Client sends some string, server manipulates it, sends it back to the client. Everything is fine but one small issue is: The client receives only the first line from server, displays it and then halts till the connection is closed by server after a time out. Although the bytes sent by server = the bytes received by client. As soon as the connection is closed, the rest of the string is displayed by the client.
I would like to know your thoughts and possible issues. Please let me know if you ahve any questions.
Protocol used: TCP
Here is the code for the server:
for (;;)
{
n=recv(s, buf, RBUFLEN-1, 0);
if (n < 0)
{
printf("Read error\n");
closesocket(s);
printf("Socket %d closed\n", s);
break;
}
else if (n==0)
{
printf("Connection closed by party on socket %d\n",s);
closesocket(s);
break;
}
else
{
printf("Received line from socket %03d : \n",s);
printf("N bytes received: %d \n",n);
// DoSomeOperationsOnTheData()
if(send(s, buffer, n, 0) != n)
printf("Write error while replying\n");
else
{
printf("Reply sent: %d bytes\n",n);
}
}
Code for client:
do
{
memset(buffer,0x0,BUFFER_SIZE); // init line
rc = read(sd, buffer, BUFFER_SIZE);
printf("\nReceived bytes: %d", rc);
if( rc > 0)
{
printf("%s",buffer);
size +=rc;
}
}while(rc>0);
printf("\n Total recieved response bytes: %d\n",size);
close(sd);
This
do
{
memset(buffer, 0, BUFFER_SIZE); // init line
rc = read(sd, buffer, BUFFER_SIZE);
printf("\nReceived bytes: %d", rc);
if( rc > 0)
{
printf("%s",buffer);
size +=rc;
}
}while(rc>0);
should be:
memset(buffer,0x0,BUFFER_SIZE); // init line
size_t size = 0;
size_t toread = BUFFER_SIZE;
do
{
ssize_t rc = read(sd, buffer+size, toread);
if (rc > 0)
{
printf("\nReceived bytes:%zd", rc);
printf("%s", buffer);
size += rc;
toread -= rc;
}
else if (rc == 0)
{
printf("The server hung up.\");
break;
}
else
{
perror("read() failed");
break;
}
} while (toread);
if (toread < BUFFERSIZE)
{
printf("Warning: Read less bytes (%zu) then expected (%d).\n", toread, BUFFERSIZE);
}
try flush data after sent.
it needs if you use socket with fdopen
FILE *fdsock = fdopen(sock, "a+");
...
fwrite(fdsock, 1, 1 "A");
fflush(fdsock);
...
fclose(fdsock);
and to finish socket, close with shutdown(sock, SD_SEND);
UPDATE
Take memset out of loop

Resources