jimo
jimo

Reputation: 602

Sending files from client to server using sockets in C

The program is supposed to send the contents of a file from the client side to an output file on the server side. However, my code is working for few files and not working for most of the files. For example if I try to copy content of a file called morefood.txt to an output file say picolo.txt, nothing is copied.

Server code:

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>

int main(int argc, char *argv[]){

  int fd =0, confd = 0;
  struct sockaddr_in serv_addr;

  char buff[1025];
  int num;

  fd = socket(AF_INET, SOCK_STREAM, 0);
  printf("Socket created\n");

  memset(&serv_addr, '0', sizeof(serv_addr));
  memset(buff, '0', sizeof(buff));

  serv_addr.sin_family = AF_INET;
  serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  serv_addr.sin_port = htons(5000);

  bind(fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
  listen(fd, 10);

  FILE* fp = fopen( "picolo.txt", "wb");

  if(fp == NULL){
      fprintf(stderr, "something went south");
      return 1;
  }

  while(1){

      confd = accept(fd, (struct sockaddr*)NULL, NULL);

      char recvbuff[10];

      int b = recv(confd, recvbuff, 10, 0);

      while(b>0)
     {
          fwrite(recvbuff, 1, b, fp);

          b = recv(confd, recvbuff, 10, 0);

     }
   close(confd);
  }

return 0;

}

Client code:

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>


int main(int argc, char *argv[]){

    int sfd =0, n=0;
    char rbuff[1024];

    struct sockaddr_in serv_addr;

    memset(rbuff, '0', sizeof(rbuff));
    sfd = socket(AF_INET, SOCK_STREAM, 0);

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(5000);
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

    connect(sfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));

    FILE *fp = fopen("morefood.txt", "rb");

    if(fp == NULL){
        fprintf(stderr, "oh no!");
        return 1;
    }

    char sendbuffer[100];

    int b = fread(sendbuffer, 1, sizeof(sendbuffer), fp);

    while(!feof(fp)){
        send(sfd, sendbuffer, b, 0);
        b = fread(sendbuffer, sizeof(sendbuffer), 1, fp);
    }

    return 0;

   }

Upvotes: 5

Views: 16545

Answers (3)

Mohit Sharma
Mohit Sharma

Reputation: 348

Part to read from file in server

    .
    .  // Your other code
    .
    read(client, rbuff, sizeof(rbuff); //Getting file name from client
    printf("File wanted by client%s\n", textToRec);
    int filedesc = open(textToRec, O_RDONLY); //Opening the file
    struct stat sb;  //To get the size of file

    if (lstat(ruff, &sb) == -1) {
        exit(EXIT_FAILURE);
    }
    long long fsize;
    fsize = sb.st_size;
    if ((0 == filedesc)) {
        fprintf(stderr,"error in reading file");
        exit(-1);
    }
    write(client, fsize, sizeof(fsize)); //Sending Filesize
    read(filedesc, sendbuffer, fsize);  //Putting file in buffer
    write(client, sendbuffer, sizeof(sendbuffer));  //Sending buffer to client
    
    close(socketid);
    .
    .
    .  // Your code

Part on the client side:

   /* your code above */
    printf("file name sent...Now wait!\n");
// I am assuming you put filename in buff
    read(sock, buff,sizeof(buff)); //Receiving file size
    long long fsize = strtol(buff,NULL,10);
    read(sock, buff,sizeof(buff)); 
    /*It's better to use sizeof instead of actual number as you can change the size of buffer anytime without needing to change values everywhere */
    int filedesc;
    filedesc =
        open(textToSend, O_WRONLY | O_APPEND | O_CREAT, 0644);
    if (!filedesc) {
        printf("failed to create file\n");
        exit;
    }
    write(filedesc, buff, fsize);
    close(filedesc);
    close(confd);

Upvotes: 0

Sir Jo Black
Sir Jo Black

Reputation: 2096

The issue is that both transmission and reception loop are bugged! I've modified them in a way that the codes run better, but I think there's a lot to modify to have a solid code!

Client:

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>

int main(int argc, char *argv[]){

    int sfd =0, n=0, b;
    char rbuff[1024];
    char sendbuffer[100];

    struct sockaddr_in serv_addr;

    memset(rbuff, '0', sizeof(rbuff));
    sfd = socket(AF_INET, SOCK_STREAM, 0);

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(5000);
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

    b=connect(sfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
    if (b==-1) {
        perror("Connect");
        return 1;
    }

    FILE *fp = fopen("prova.jpg", "rb");
    if(fp == NULL){
        perror("File");
        return 2;
    }

    while( (b = fread(sendbuffer, 1, sizeof(sendbuffer), fp))>0 ){
        send(sfd, sendbuffer, b, 0);
    }

    fclose(fp);
    return 0;

}

Server:

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>

int main(int argc, char *argv[]){

    int fd =0, confd = 0,b,tot;
    struct sockaddr_in serv_addr;

    char buff[1025];
    int num;

    fd = socket(AF_INET, SOCK_STREAM, 0);
    printf("Socket created\n");

    memset(&serv_addr, '0', sizeof(serv_addr));
    memset(buff, '0', sizeof(buff));

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(5000);

    bind(fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
    listen(fd, 10);

    while(1){
        confd = accept(fd, (struct sockaddr*)NULL, NULL);
        if (confd==-1) {
            perror("Accept");
            continue;
        }
        FILE* fp = fopen( "provacopy.jpg", "wb");
        tot=0;
        if(fp != NULL){
            while( (b = recv(confd, buff, 1024,0))> 0 ) {
                tot+=b;
                fwrite(buff, 1, b, fp);
            }

            printf("Received byte: %d\n",tot);
            if (b<0)
               perror("Receiving");

            fclose(fp);
        } else {
            perror("File");
        }
        close(confd);
    }

    return 0;
}

Upvotes: 6

user3629249
user3629249

Reputation: 16550

this code, in the client:

char sendbuffer[100];

int b = fread(sendbuffer, 1, sizeof(sendbuffer), fp);

while(!feof(fp)){
    send(sfd, sendbuffer, b, 0);
    b = fread(sendbuffer, sizeof(sendbuffer), 1, fp);
}

is not a good way to send a 'nameless' file.

I suggest

while( 0< (byteCount = fread( sendbuffer, sizeof(sendbuffer), 1, fp) ) )
{
    send(sfd, sendbuffer, byteCount, 0);
}

however, for robustness

--client send a file name and total file size with recordNum 0
--server when receiving recordNum 0
  open the appropriate file name
  if successful open, send 'ack', maxRecordSize echo recordNum
  else send 'nak' echo recordNum
--client, on following records, 
  send byteCount, recordNum, data
--server respond with 'ack' for each received record
  when it is expected recordNum
  otherwise respond with 'nak' expected recordNum
--when client receives 'ack' send next record
--when client receives 'nak' resend prior record
--client, after all file sent, send file checksum with recordnum -1
--server, when receive recordNum -1 compares checksum, closes file
  responds with final 'ack' if checksum matches
  responds with final 'nak' if checksum does not match

This 'lockstep' communication, which is often used in the real world, will assure both ends of the communication know what is going on and will assure a successful file transfer,

This works for only one file being sent at a time. for multiple files being sent at the same time, the records will need another field, that indicates which file 'this' record is part of.

of course, all send/recv/open/connect/bind/ etc system function calls need to have the returned value(s) checked for errors

Upvotes: 2

Related Questions