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

时间:2010-07-28 18:35:00

标签: c file sockets client-server

我正在与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。

3 个答案:

答案 0 :(得分:2)

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

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

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

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

是的,分配msg.buffer[msg.size] = '\0'是必要的,因为open需要名称末尾的'\0'字符(知道名字结束的位置)。


  

我认为strcpy可能是合适的

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

答案 1 :(得分:1)

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

编辑:

@Amardeep这里有更好的眼睛看着我 - 你正在用strcpy(3)破坏你的内存到filename指针变量指向的空间,看起来像未初始化。

答案 2 :(得分:0)

我已经找到了答案,或者至少是接近它的东西。首先,一个换行符正在发送。在客户端,我使用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特别有用 - 以前从未使用过它)