请帮助我理解为什么这个函数在到达fclose时抛出异常:
void receive_file(int socket, char *save_to, int file_size) {
FILE *handle = fopen(save_to,"wb");
if(handle != NULL) {
int SIZE = 1024;
char buffer[SIZE];
memset(buffer,0,SIZE);
int read_so_far = 0;
int read_now = 0;
int reading_unit = (file_size < SIZE) ? file_size : SIZE;
do {
read_now = read(socket,buffer,reading_unit);
fwrite(buffer,read_now,1,handle);
read_so_far += read_now;
if(read_so_far >= file_size) {
break;
}
memset(buffer, 0, sizeof(buffer));
} while (1);
read_now = 0;
fclose(handle);
}
else {
extern int errno;
printf("error creating file");
printf(" error code : %d",errno);
exit(-1);
}
}
Eclipse CDT存在以下错误:
Single stepping until exit from function __kernel_vsyscall, which has no line number information.
此功能的目的是通过套接字接收文件。
编辑:我正在使用CentOS 5.3。问题是,文件是创建和编写的。即使MD5也是正确的。我不明白为什么它在fclose失败了。EDIT2:这是我设法获得的堆栈跟踪:
*** glibc detected *** /home/linuser/workspace/proj/Debug/proj: free(): invalid next size (normal): 0x096a0068 *** ======= Backtrace: ========= /lib/libc.so.6[0x4fb0f1] /lib/libc.so.6(cfree+0x90)[0x4febc0] /lib/libc.so.6(fclose+0x136)[0x4e9c56] /home/linuser/workspace/proj/Debug/proj[0x8048cd8] /home/linuser/workspace/proj/Debug/proj[0x80492d6] /home/linuser/workspace/proj/Debug/proj[0x804963d] /lib/libc.so.6(__libc_start_main+0xdc)[0x4a7e8c] /home/linuser/workspace/proj/Debug/proj[0x8048901] ======= Memory map: ======== 001ff000-00200000 r-xp 001ff000 00:00 0 [vdso] 0046f000-00489000 r-xp 00000000 08:06 1280361 /lib/ld-2.5.so 00489000-0048a000 r-xp 00019000 08:06 1280361 /lib/ld-2.5.so 0048a000-0048b000 rwxp 0001a000 08:06 1280361 /lib/ld-2.5.so 00492000-005d0000 r-xp 00000000 08:06 1280362 /lib/libc-2.5.so 005d0000-005d2000 r-xp 0013e000 08:06 1280362 /lib/libc-2.5.so 005d2000-005d3000 rwxp 00140000 08:06 1280362 /lib/libc-2.5.so 005d3000-005d6000 rwxp 005d3000 00:00 0 005d8000-005fd000 r-xp 00000000 08:06 1280369 /lib/libm-2.5.so 005fd000-005fe000 r-xp 00024000 08:06 1280369 /lib/libm-2.5.so 005fe000-005ff000 rwxp 00025000 08:06 1280369 /lib/libm-2.5.so 009b2000-009bd000 r-xp 00000000 08:06 1280372 /lib/libgcc_s-4.1.2-20080825.so.1 009bd000-009be000 rwxp 0000a000 08:06 1280372 /lib/libgcc_s-4.1.2-20080825.so.1 009c5000-00aa5000 r-xp 00000000 08:06 5465873 /usr/lib/libstdc++.so.6.0.8 00aa5000-00aa9000 r-xp 000df000 08:06 5465873 /usr/lib/libstdc++.so.6.0.8 00aa9000-00aaa000 rwxp 000e3000 08:06 5465873 /usr/lib/libstdc++.so.6.0.8 00aaa000-00ab0000 rwxp 00aaa000 00:00 0 08048000-0804a000 r-xp 00000000 08:06 4884214 /home/linuser/workspace/proj/Debug/proj 0804a000-0804b000 rw-p 00001000 08:06 4884214 /home/linuser/workspace/proj/Debug/proj 096a0000-096c1000 rw-p 096a0000 00:00 0 [heap] b7e00000-b7e21000 rw-p b7e00000 00:00 0 b7e21000-b7f00000 ---p b7e21000 00:00 0 b7f99000-b7f9a000 rw-p b7f99000 00:00 0 b7faa000-b7fac000 rw-p b7faa000 00:00 0 bfa82000-bfa97000 rw-p bffea000 00:00 0 [stack]
这是该功能的“更新”版本:
void rec_file(int socket,char *path,int size)
{
FILE *handle = fopen(path,"wb");
char buffer[4096];
int total_read = 0;
if(handle != NULL)
{
while(1)
{
int bytes_read = recv(socket,buffer,4096,0);
total_read += bytes_read;
if(bytes_read != -1)
{
fwrite(buffer,bytes_read,1,handle);
}
else
{
printf("read error ");
exit(-1);
}
if(total_read >= size)
{
break;
}
}
fclose(handle);
}
else
{
printf("error receiving file");
exit(-1);
}
}
也许这更干净?但是,我仍然收到相同的fclose异常。
EDIT3: 我注释掉了所有内容,我只留下了下面的代码,遗憾的是,它仍然在fclose中抛出异常:
void nrec(int sock,char* path,int size)
{
FILE *handle = fopen(path,"wb");
if(handle == NULL)
{
printf ("error opening file");
return;
}
fclose(handle);
}
答案 0 :(得分:6)
fclose()返回一个值:如果文件成功关闭则返回0,否则返回EOF。考虑将代码修改为...
if(fclose(handle)){printf(“error closing file。”);出口(-1); }
正如其他人所指出的,请检查read()是否有错误。
如果在之后发生崩溃,fclose返回0(成功),并且所有read()都成功,那么问题可能就在其他地方。也许这是VLA。考虑将缓冲区代码更改为静态文件或malloc / free。
如果调用者误解了文件大小,比如声称该文件是500字节,实际上只有480字节,那么你的代码是否会永远读取套接字?
答案 1 :(得分:2)
这段代码似乎非常......不确定自己。许多不必要的作业,memset()
来电,复杂的逻辑。
限制您尝试阅读的金额没有意义。总是读取尽可能多的缓冲空间;如果可用的数据较少,您将获得更少的数据。
它也无法正确处理错误。如果read()
失败,它可以返回-1,在这种情况下Bad Things(TM)将在整个地方发生。
我的建议是清理它,考虑I / O函数的返回值并更好地检查它们,然后再试一次。
如果你没有,如果你在Linux中,请通过Valgrind运行它以获得帮助来追踪崩溃。
答案 2 :(得分:2)
不确定,但你知道read()可以在错误时返回否定,对吗?
答案 3 :(得分:2)
您没有检查read()
来电是否收到错误提示。如果从read()
获得-1,则将其取消选中,传递给fwrite()
,其中size_t
为其参数。当您的int
值转换为size_t
(或视为size_t
)时,它会变为相当大的数字(32位系统上为4 GB - 1)。因此,fwrite()
会按照您的命令执行 - 尝试从不应该的地方写入大量数据。
答案 4 :(得分:1)
您需要测试read()的返回值 - 它可能会返回错误代码,例如-1,以及读取的字节数。
编辑:在新代码中,您应该测试recv()的返回值是&gt; = 0,而不是-1。如果它返回零,你应该打破。
答案 5 :(得分:1)
edit3中的代码看起来很合理。我怀疑你可能在其他地方踩过一些内存,并且在你的应用程序中正在收获这个问题。
你是否有使用免费内存块等运行来检查缓冲区溢出的检查器,净化等等。
答案 6 :(得分:1)
在开始使用此功能之前,您确定没有在其他地方损坏堆吗?尝试在valgrind下运行你的程序。
答案 7 :(得分:1)
如果您的“EDIT3”版本的代码仍然崩溃,那么问题就出在代码的其他地方。如果你在程序的另一部分中犯了一个错误(例如,释放了两次,取消引用了一个没有指向你想象的指针),那么直到后来才能看到由此产生的损坏(比如当你到达时) FCLOSE())。
答案 8 :(得分:0)
可能是因为你在文件中写的字节比file_size多吗?如果您将file_size设置为1025,则使用当前逻辑,然后您将最终写入2048字节到该文件。我相信,你应该重新计算while循环中的reading_unit。
答案 9 :(得分:0)
我不确定编译器将如何解释这两行
int SIZE = 1024;
char buffer[SIZE];
您正在使用变量来调整缓冲区大小而不是常量。我不确定这是否会像你期望的那样。您可以尝试以下方式吗。
#define SIZE (1024)
char buffer[SIZE];