C++ 使用文件指针通过TCP传输文件时出现的问题

C++ 使用文件指针通过TCP传输文件时出现的问题,c++,unix,network-programming,C++,Unix,Network Programming,我需要通过TCP传输一个8.3MB的文件,当我使用文件指针读写文件时,我发送大约8.6MB的数据,并通过计算发送和接收调用的输出来接收8.6MB的数据。虽然我的文件大小是8.3MB,但当我通过查看其属性来单独检查文件大小时,它大约是3-5MB(每次转让时有所不同)但是,当我使用文件描述符代替文件指针时,我发送和接收的数据正好是8.3MB,文件属性大小也显示为8.3MB。那么,使用文件指针有什么问题,为什么在使用文件描述符时会将其删除……但是如果我使用文件描述符,那么我就无法读取我发送的文本文件。

我需要通过TCP传输一个8.3MB的文件,当我使用文件指针读写文件时,我发送大约8.6MB的数据,并通过计算发送和接收调用的输出来接收8.6MB的数据。虽然我的文件大小是8.3MB,但当我通过查看其属性来单独检查文件大小时,它大约是3-5MB(每次转让时有所不同)但是,当我使用文件描述符代替文件指针时,我发送和接收的数据正好是8.3MB,文件属性大小也显示为8.3MB。那么,使用文件指针有什么问题,为什么在使用文件描述符时会将其删除……但是如果我使用文件描述符,那么我就无法读取我发送的文本文件。文本编辑器显示文件中有一些二进制数据。我一点也不了解正在发生的事情…请提前帮助和感谢

server.cpp
#包括“server.h”
void服务器()
{
int fd=打开(“out.txt”,仅限O_wr);
sin中的结构sockaddr_;
袜子尺寸;
char buf[MAX_LINE];
内伦;
国际标准,新标准;
/*构建地址数据结构*/
bzero((char*)和sin,sizeof(sin));
sin.sin_family=AF_INET;
sin.sin\u addr.s\u addr=INADDR\u ANY;
sin.sin_端口=htons(服务器_端口);
printf(“文件描述符:%d”,fd);
/*设置被动打开*/
if((s=socket(PF_INET,SOCK_STREAM,0))<0)
{
perror(“单工通话:插座”);
出口(1);
}
if((bind(s,(struct sockaddr*)&sin,sizeof(sin)))<0)
{
perror(“单工对话:绑定”);
出口(1);
}
倾听(s,MAX_待定);
//等待连接,然后接收并打印文本*/
而(1)
{
如果((新建=接受,(结构sockaddr*)和sin,&addr\u大小))<0)
{
perror(“单工对话:接受”);
出口(1);
}
浮动总数=0;
printf(“文件描述符:%d”,fd);
而(len=recv(新的、基本的、最大的线,0)和strcmp(基本的、关闭的))
{
buf[len]=0;
总计=总计+长度;
//写入(标准输出、buf、len);
写入(fd、buf、len);
//printf(“%fKB和%fMB\n”,总计/1024,总计/(1024*1024));
}
printf(“文件描述符:%d”,fd);
关闭(纽约);
}
}
client.cpp
#包括“client.h”
无效客户端(整型argc,字符**argv)
{
int fd=open(“/home/nikku/Desktop/data.txt”,仅限ordu);
如果(fd<0)perror(“文件未打开”\n);
结构主机*hp;
sin中的结构sockaddr_;
字符*主机;
char buf[MAX_LINE];
int-s;
内伦;
主机=argv[1];
如果(argc==2)
{
主机=argv[1];
}
其他的
{
fprintf(stderr,“用法:单工对话主机\n”);
出口(1);
}
/*将主机名转换为对等方的IP地址*/
gethostname(主机,20);
printf(“%s\n”,主机);
hp=gethostbyname(主机);
如果(!hp)
{
fprintf(stderr,“单工对话:未知主机:%s\n”,主机);
出口(1);
}
/*构建地址数据结构*/
bzero((char*)和sin,sizeof(sin));
sin.sin_family=AF_INET;
b复制(hp->h_地址,(字符*)和sin.sin_地址,hp->h_长度);
sin.sin_端口=htons(服务器_端口);
/*主动开放*/
if((s=socket(PF_INET,SOCK_STREAM,0))<0)
{
perror(“单工通话:插座”);
出口(1);
}
if(connect(s,(struct sockaddr*)&sin,sizeof(sin))<0)
{
perror(“单工对话:连接”);
关闭(s);;
出口(1);
}
printf(“连接成功\n”);
/*主循环:获取和发送文本行*/
浮动总数=0;
while(读取(fd、buf、MAX_行))
{
//usleep(1000);;
len=strlen(buf)+1;
总计+=发送(s,buf,len,0);
//printf(“%fKB和%fMB\n”,总计/1024,总计/(1024*1024));
}
发送(s,“关闭”,6,0);
关闭(fd);
}
如果我用指针代替文件描述符的使用,并使用FGET和FPUT进行读写,那么我的文件传输就无法正常进行。但是如果我使用文件描述符,那么我就无法读取发送的文本文件。文本编辑器会在文件中显示一些二进制数据

while (read(fd, buf, MAX_LINE))
{
    //usleep(1000);;
    len = strlen(buf) + 1;
    total += send(s, buf, len, 0);
    //printf("%fKB and %fMB\n",total/1024, total/(1024*1024));
}
这里有一个问题,您不能保证
read
将读取一个零字节,因此
strlen(buf)
具有潜在危险。另外请注意,当您将
len
设置为
strlen(buf)时+1
,如果您遇到零字节,您将通过套接字发送它,但如果您不读取零字节,
strlen
将读取数组末尾以外的内容,并通过套接字发送“垃圾”

存储
read
的返回值是明智的,这样您就可以知道实际从
fd
读取了多少字节

while (len = recv(new_s, buf, MAX_LINE, 0) && strcmp(buf,"close"))
{
    buf[len] = 0;
    total = total+len;
    //write(stdout, buf, len);
    write(fd, buf, len);
    //printf("%fKB and %fMB\n",total/1024, total/(1024*1024));
}
您的接收端似乎认为,当您手动使用0终止缓冲区时,对recv的每次调用都不会包含零字节。请注意,如果
recv
实际接收
MAX_LINE
字节,则实际上没有空间这样做,因为
buf
仅包含
MAX_LINE
元素。因为您的写入受到长度在任何情况下,都不需要执行
buf[len]=0;

这里有一个问题,您不能保证
read
将读取一个零字节,因此
strlen(buf)
具有潜在危险。另外请注意,当您将
len
设置为
strlen(buf)时+1
,如果您遇到零字节,您将通过套接字发送它,但如果您不读取零字节,
strlen
将读取数组末尾以外的内容,并通过套接字发送“垃圾”

存储
read
的返回值是明智的,这样您就可以知道实际从
fd
读取了多少字节

while (len = recv(new_s, buf, MAX_LINE, 0) && strcmp(buf,"close"))
{
    buf[len] = 0;
    total = total+len;
    //write(stdout, buf, len);
    write(fd, buf, len);
    //printf("%fKB and %fMB\n",total/1024, total/(1024*1024));
}
您的接收端似乎认为,当您手动使用0终止缓冲区时,对recv的每次调用都不会包含零字节。请注意,如果
recv
实际接收
MAX,您实际上没有空间这样做_
while (len = recv(new_s, buf, MAX_LINE, 0) && strcmp(buf,"close"))
{
    buf[len] = 0;
    total = total+len;
    //write(stdout, buf, len);
    write(fd, buf, len);
    //printf("%fKB and %fMB\n",total/1024, total/(1024*1024));
}