服务器无法正确读取/打开客户端在C中发送的文件名

我正在与C中的套接字进行客户端/服务器交互。我要做的是让客户端请求在服务器上读取文件,服务器返回文件内容的缓冲区,客户端打印出来文件。

虽然我能够完成服务器向客户端发送文件缓冲区并且客户端成功打印出来,但我似乎无法让服务器成功读取客户端发送的文件名。

这就是我的意思:

///This is the structure of the message that gets sent back and forth struct message { int code; //Just indicates 1 or 2 for readfile or writefile int size; char buffer[256]; //This will hold the filename when client sends readfile request }; 

作品:

 char *filename = "test.c"; infile = open(filename, O_RDONLY); //Send the file and everything back to the client 

不起作用:

 while( read(sockfd, &msg, sizeof(int) * 2) > 0) { if(msg.code == 1) { //Perform a read operation int infile, filesize, rr; int length; char output[256]; size_t rb = 0; while(rb < msg.size) { ssize_t r = read(sockfd, msg.buffer, msg.size - rb); if(r < 0) { error(sockfd, r, msg.buffer); break; } rb += r; } msg.buffer[rb] = '\0'; //This has been printing out the correct amount printf("\nBytes read: %i", rb); //This has also been printing out properly printf("\nmsg.buffer: %s", msg.buffer); infile = open(msg.buffer, O_RDONLY); 

我已编辑显示我的程序所处的当前状态,但仍然无效。 以前,我有一个不正确放置的strcpy。

在您发布的代码中, filename未初始化。 您的编译器应该已经警告过您。 如果没有,你就没有正确地调用它; 用gcc ,至少做gcc -O -Wall

如果使用strcpy还需要为文件名分配内存。 在简单的程序中不需要这一步骤; 如果您在从客户端继续阅读后需要记住文件名,那么制作副本会很有用。 strdup函数将内存分配与字符串复制相结合,这在这里是合适的。

您需要检查所有系统调用的返回值。 read的返回值告诉您read了多少字节。 如果操作系统感觉如此,则允许read(fd,buf,n)的调用返回少于n个字节。 如果您收到的字节数少于预期,请在循环中调用read 。 是的,几乎所有调用read程序都在循环中调用它,这是一个基本的Unix / POSIX习惯用法。 freadfunction可以帮助你,如果你能适应它。

缺少检查msg.codemsg.size有效性的代码。 由于您已在msg.buffer分配了256个字节, msg.buffer必须将msg.size限制为255。

是的,赋值msg.buffer[msg.size] = '\0'是必要的,因为open需要名称末尾的'\0'字符(这就是它知道名称结束的方式)。


我想也许strcpy是合适的

每当你在指针周围时(大部分时间都是在C中),你需要仔细考虑你正在做什么以及这些指针指向的位置,以及那里是否有足够的空间来放置你想要的东西。 C是一种无情的语言; 投掷指针和投掷箭头一样危险。 画图! 有两种C程序员:在白板,纸上,沙子或其他媒介上绘制图表的人; 以及那些在他们头脑中绘制图表的人(第三种仍在试图弄清楚为什么他们的打印1+1正在打印3 )。

您没有检查read(2)返回值 ,它告诉您已读取了多少字节, – 您的消息可能无法完整读取,因此文件名可能会被截断。

编辑:

@Amardeep这里有更好的眼睛他们 – 你用strcpy(3)破坏你的记忆到filename指针变量指向的空间,看起来像未初始化。

好吧,我已经找到了答案,或者至少是接近它的东西。 首先,一个换行符正在发送。 在客户端,我使用了fgets(msg.buffer, 256, stdin); 得到消息。 当我使用printf("File |%s|", msg.buffer)检查值时,我看到第二个栏位于下一行。 我接受了那个换行符,最后用空字符覆盖了它。

我也改为fopen和freads / writes。 我将./添加到文件语句的开头,但我怀疑是否需要…这只是我之前的尝试之一。 它现在看起来像这样:

  size_t rb = 0; FILE* file; char filename[256]; while(rb < msg.size) { ssize_t r = read(sockfd, filename, msg.size - rb); if(r < 0) { error(sockfd, r, msg.buffer); goto end; } rb += r; } if(strlen(filename) > 253) { error(sockfd, rb, msg.buffer); goto end; } strcpy(msg.buffer, "./"); strcat(msg.buffer, filename); msg.buffer[rb + 1] = '\0'; file = fopen(msg.buffer, "r"); if(file == NULL) { error(sockfd, rb, msg.buffer); printf("Error opening file %s: %s\n", msg.buffer,strerror(errno)); fflush(stdout); goto end; } 

感谢所有帮助过的人。 我学到了很多东西(gdb特别有用 – 我之前从未使用过它)