C 使用套接字发送和接收文件

C 使用套接字发送和接收文件,c,sockets,C,Sockets,客户端在接收文件时使用这部分代码: void do_retr_cmd(int f_sockd){ int fd; ssize_t nread = 0; uint32_t fsize, fsize_tmp, total_bytes_read, size_to_receive; char *filename = NULL, *conferma = NULL, *filebuffer = NULL; char buf[256], dirp[256], t_buf[256];

客户端在接收文件时使用这部分代码:

void do_retr_cmd(int f_sockd){
  int fd;
  ssize_t nread = 0;
  uint32_t fsize, fsize_tmp, total_bytes_read, size_to_receive;
  char *filename = NULL, *conferma = NULL, *filebuffer = NULL;
  char buf[256], dirp[256], t_buf[256];

  memset(dirp, 0, sizeof(dirp));
  memset(buf, 0, sizeof(buf));
  memset(t_buf, 0, sizeof(t_buf));
  printf("Write the name of file to download: ");
  fgets(dirp, BUFFGETS, stdin)
  filename = NULL;
  filename = strtok(dirp, "\n");
  sprintf(buf, "RETR %s", dirp);
  if(send(f_sockd, buf, strlen(buf), 0) < 0){
    perror("Errore durante l'invio del nome del file");
    onexit(f_sockd, 0, 0, 1);
  }
  fsize = 0;
  recv(f_sockd, t_buf, sizeof(t_buf), 0)
  fsize = atoi(t_buf);
  fd = open(filename, O_CREAT | O_WRONLY, 0644);
  fsize_tmp = fsize;
  filebuffer = (char *)malloc(fsize);
  total_bytes_read = 0;
  nread = 0;
  for(size_to_receive = fsize; size_to_receive > 0;){
    nread = read(f_sockd, filebuffer, size_to_receive);
    if(nread < 0){
      perror("read error on retr");
      onexit(f_sockd, 0, 0, 1);
    }
    if(write(fd, filebuffer, nread) != nread){
      perror("write error on retr");
      onexit(f_sockd, 0, 0, 1);
    }
    size_to_receive -= nread;
  }
  close(fd);
  fflush(stdout);
  fflush(stdin);
  memset(buf, 0, sizeof(buf));
  recv(f_sockd, buf, 21, 0)
  printf("%s", buf);
  memset(buf, 0, sizeof(buf));
  memset(t_buf, 0, sizeof(t_buf));
  memset(dirp, 0, sizeof(dirp));
  free(filebuffer);
}
void do_server_retr_cmd(f_sockd, m_sockd){
  int fd, rc;
  uint32_t fsize, size_to_send;
  char *filename = NULL, *other = NULL;
  char buf[512], t_buf[256];
  off_t offset;
  struct stat fileStat;

  memset(buf, 0, sizeof(buf));
  memset(t_buf, 0, sizeof(t_buf));
  recv(f_sockd, buf, sizeof(buf), 0)
  other = NULL;
  filename = NULL;
  other = strtok(buf, " ");
  filename = strtok(NULL, "\n");

  if(strcmp(other, "RETR") == 0){
    printf("Ricevuta richiesta RETR\n");
  } else /* do something */

  fd = open(filename, O_RDONLY);

  memset(&fileStat, 0, sizeof(fileStat));
  fileStat.st_size = 0;
  fstat(fd, &fileStat)
  fsize = fileStat.st_size;
  snprintf(t_buf, 255, "%" PRIu32, fsize);
  send(f_sockd, t_buf, sizeof(t_buf), 0)
  offset = 0;
  for (size_to_send = fsize; size_to_send > 0; ){
    rc = sendfile(f_sockd, fd, &offset, size_to_send);
    if (rc <= 0){
      perror("sendfile");
      onexit(f_sockd, m_sockd, fd, 3);
    }
    size_to_send -= rc;
  }
  close(fd);
  fflush(stdout);
  fflush(stdin);
  memset(buf, 0, sizeof(buf));
  strcpy(buf, "226 File transfered\n");
  send(f_sockd, buf, strlen(buf), 0)
  memset(buf, 0, sizeof(buf));
  memset(t_buf, 0, sizeof(t_buf));
}
void do_retr_cmd(int f_sockd){
int-fd;
ssize_t nread=0;
uint32 fsize、fsize\u tmp、读取的总字节数、接收的大小;
char*filename=NULL,*conferma=NULL,*filebuffer=NULL;
char-buf[256],dirp[256],t_-buf[256];
memset(dirp,0,sizeof(dirp));
memset(buf,0,sizeof(buf));
memset(t_buf,0,sizeof(t_buf));
printf(“写下要下载的文件名:”);
FGET(dirp、BUFFGETS、stdin)
filename=NULL;
filename=strtok(dirp,“\n”);
sprintf(buf,“RETR%s”,dirp);
如果(发送(f_sockd,buf,strlen(buf),0)<0){
perror(“文件因维奥而出错”);
onexit(f_-sockd,0,0,1);
}
fsize=0;
记录(f_sockd,t_buf,sizeof(t_buf),0)
fsize=atoi(t_buf);
fd=打开(文件名,O|u CREAT | O|u WRONLY,0644);
fsize_tmp=fsize;
filebuffer=(char*)malloc(fsize);
读取的总字节数=0;
nread=0;
对于(大小到接收=fsize;大小到接收>0;){
nread=读取(f_sockd,filebuffer,size_to_receive);
如果(nread<0){
perror(“retr上的读取错误”);
onexit(f_-sockd,0,0,1);
}
if(写入(fd,filebuffer,nread)!=nread){
perror(“retr上的写入错误”);
onexit(f_-sockd,0,0,1);
}
大小\u至\u接收-=nread;
}
关闭(fd);
fflush(stdout);
fflush(stdin);
memset(buf,0,sizeof(buf));
记录(f_sockd,buf,21,0)
printf(“%s”,buf);
memset(buf,0,sizeof(buf));
memset(t_buf,0,sizeof(t_buf));
memset(dirp,0,sizeof(dirp));
免费(文件缓冲区);
}
这部分代码由服务器在发送文件时使用:

void do_retr_cmd(int f_sockd){
  int fd;
  ssize_t nread = 0;
  uint32_t fsize, fsize_tmp, total_bytes_read, size_to_receive;
  char *filename = NULL, *conferma = NULL, *filebuffer = NULL;
  char buf[256], dirp[256], t_buf[256];

  memset(dirp, 0, sizeof(dirp));
  memset(buf, 0, sizeof(buf));
  memset(t_buf, 0, sizeof(t_buf));
  printf("Write the name of file to download: ");
  fgets(dirp, BUFFGETS, stdin)
  filename = NULL;
  filename = strtok(dirp, "\n");
  sprintf(buf, "RETR %s", dirp);
  if(send(f_sockd, buf, strlen(buf), 0) < 0){
    perror("Errore durante l'invio del nome del file");
    onexit(f_sockd, 0, 0, 1);
  }
  fsize = 0;
  recv(f_sockd, t_buf, sizeof(t_buf), 0)
  fsize = atoi(t_buf);
  fd = open(filename, O_CREAT | O_WRONLY, 0644);
  fsize_tmp = fsize;
  filebuffer = (char *)malloc(fsize);
  total_bytes_read = 0;
  nread = 0;
  for(size_to_receive = fsize; size_to_receive > 0;){
    nread = read(f_sockd, filebuffer, size_to_receive);
    if(nread < 0){
      perror("read error on retr");
      onexit(f_sockd, 0, 0, 1);
    }
    if(write(fd, filebuffer, nread) != nread){
      perror("write error on retr");
      onexit(f_sockd, 0, 0, 1);
    }
    size_to_receive -= nread;
  }
  close(fd);
  fflush(stdout);
  fflush(stdin);
  memset(buf, 0, sizeof(buf));
  recv(f_sockd, buf, 21, 0)
  printf("%s", buf);
  memset(buf, 0, sizeof(buf));
  memset(t_buf, 0, sizeof(t_buf));
  memset(dirp, 0, sizeof(dirp));
  free(filebuffer);
}
void do_server_retr_cmd(f_sockd, m_sockd){
  int fd, rc;
  uint32_t fsize, size_to_send;
  char *filename = NULL, *other = NULL;
  char buf[512], t_buf[256];
  off_t offset;
  struct stat fileStat;

  memset(buf, 0, sizeof(buf));
  memset(t_buf, 0, sizeof(t_buf));
  recv(f_sockd, buf, sizeof(buf), 0)
  other = NULL;
  filename = NULL;
  other = strtok(buf, " ");
  filename = strtok(NULL, "\n");

  if(strcmp(other, "RETR") == 0){
    printf("Ricevuta richiesta RETR\n");
  } else /* do something */

  fd = open(filename, O_RDONLY);

  memset(&fileStat, 0, sizeof(fileStat));
  fileStat.st_size = 0;
  fstat(fd, &fileStat)
  fsize = fileStat.st_size;
  snprintf(t_buf, 255, "%" PRIu32, fsize);
  send(f_sockd, t_buf, sizeof(t_buf), 0)
  offset = 0;
  for (size_to_send = fsize; size_to_send > 0; ){
    rc = sendfile(f_sockd, fd, &offset, size_to_send);
    if (rc <= 0){
      perror("sendfile");
      onexit(f_sockd, m_sockd, fd, 3);
    }
    size_to_send -= rc;
  }
  close(fd);
  fflush(stdout);
  fflush(stdin);
  memset(buf, 0, sizeof(buf));
  strcpy(buf, "226 File transfered\n");
  send(f_sockd, buf, strlen(buf), 0)
  memset(buf, 0, sizeof(buf));
  memset(t_buf, 0, sizeof(t_buf));
}
void do_server_retr_cmd(f_sockd,m_sockd){
int-fd,rc;
uint32尺寸,发送的尺寸;
char*filename=NULL,*other=NULL;
char-buf[512],t_-buf[256];
偏移量;
struct stat fileStat;
memset(buf,0,sizeof(buf));
memset(t_buf,0,sizeof(t_buf));
记录(f_sockd,buf,sizeof(buf),0)
其他=空;
filename=NULL;
其他=strtok(buf,“”);
filename=strtok(空,“\n”);
如果(strcmp(其他,“RETR”)==0){
printf(“Ricevuta richiesta RETR\n”);
}否则做点什么*/
fd=打开(仅文件名);
memset(&fileStat,0,sizeof(fileStat));
fileStat.st_size=0;
fstat(fd和fileStat)
fsize=fileStat.st\u size;
snprintf(t_buf,255,“%”PRIu32,fsize);
发送(f_sockd,t_buf,sizeof(t_buf),0)
偏移量=0;
对于(大小\u至\u发送=fsize;大小\u至\u发送>0;){
rc=sendfile(f_sockd、fd和offset、大小_到_send);

如果省略了(rc错误检查)TCP连接为您提供了可靠的双向字节流,但“应用程序消息”的边界没有保留,这意味着一个
send()
可以在另一侧的多个
recv()
中接收,反之,可以接收多个
send()
s可以折叠成一个
recv()
(您可以接收最后发送的数据块的一部分)。好的是您确实可以按照发送的顺序接收发送的字节

服务器代码中的行
recv(f_sockd,buf,sizeof(buf),0);
假定您在此处读取文件名,而实际上,您最多可以获取客户端发送的任何内容的
256
字节

您需要在纯TCP之上强加某种应用程序级协议。一个非常简单的方法是在文件内容前面发送一个文本头,格式如下:

file-size file-name\n
因此,您的服务器可以查找第一个换行符,在第一个空格中拆分该行,并具有预期的字节数和保存这些字节的文件名。不要忽略该换行符后接收缓冲区的其余部分,请将其保存到文件中。这也使您可以将该连接重新用于多个文件传输


希望这有帮助。

TCP连接为您提供了可靠的双向字节流,但您的“应用程序消息”的边界没有保留,这意味着一个
send()
可以在另一端的多个
recv()
中接收,反之,可以接收多个
send()
s可以折叠成一个
recv()
(您可以接收最后发送的数据块的一部分)。好的是您确实可以按照发送的顺序接收发送的字节

recv(f_sockd, buf, 21, 0)
printf("%s", buf);
服务器代码中的行
recv(f_sockd,buf,sizeof(buf),0);
假定您在此处读取文件名,而实际上,您最多可以获取客户端发送的任何内容的
256
字节

您需要在纯TCP之上强加某种应用程序级协议。一个非常简单的方法是在文件内容前面发送一个文本头,格式如下:

file-size file-name\n
因此,您的服务器可以查找第一个换行符,在第一个空格中拆分该行,并具有预期的字节数和保存这些字节的文件名。不要忽略该换行符后接收缓冲区的其余部分,请将其保存到文件中。这也使您可以将该连接重新用于多个文件传输

希望这有帮助

recv(f_sockd, buf, 21, 0)
printf("%s", buf);
这个
printf
打印大量随机垃圾,因为没有实际的协议来控制它接收什么和打印什么。例如,
printf
如何知道要打印多少字节


这个
printf
打印了大量随机垃圾,因为没有实际的协议来控制它接收的内容和打印的内容。例如,
printf
如何知道要打印多少字节?

我以前的回答不太正确,但这就是为什么你会看到这种奇怪的行为。你发送文件大小为

snprintf(t_buf, 255, "%" PRIu32, fsize);
然后,您将收到

recv(f_sockd, t_buf, sizeof(t_buf), 0)
但这并不能保证实际读取
sizeof(t_buf)
字节。然后
atoi
有时会返回不正确的大小,文件的其余部分被视为状态消息,并在最后打印(直到第一个空字符)

因为
recv