使用C中的套接字将文件从客户端发送到服务器

时间:2015-05-25 14:04:27

标签: c network-programming

程序应该将文件的内容从客户端发送到服务器端的输出文件。但是,我的代码适用于少数文件而不适用于大多数文件。例如,如果我尝试将名为morefood.txt的文件的内容复制到输出文件picolo.txt,则不会复制任何内容。

服务器代码:

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

}

客户代码:

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

   }

3 个答案:

答案 0 :(得分:2)

此代码,在客户端:

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

不是一个发送无名&#39;的好方法。文件。

我建议

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

然而,为了稳健性

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

这个&#39;锁步&#39;通信,通常在现实世界中使用, 将确保通信的两端知道发生了什么 并确保成功的文件传输,

这适用于一次只发送一个文件。 对于同时发送的多个文件, 记录将需要另一个字段,指示哪个文件 &#39;这&#39;记录是其中的一部分。

当然,所有send / recv / open / connect / bind / etc系统函数调用都需要检查返回值是否有错误

答案 1 :(得分:1)

问题是传输和接收循环都被窃听!我已经以一种代码运行得更好的方式对它们进行了修改,但我认为要修改它以获得可靠的代码!

客户端:

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

}

服务器:

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

答案 2 :(得分:0)

要从服务器中的文件读取的部分

    .
    .  // 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

客户端部分:

   /* 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);