我正在与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。
答案 0 :(得分:2)
在您发布的代码中,filename
未初始化。您的编译器应该已经警告过您。如果没有,你就没有正确地调用它;使用gcc
,至少执行gcc -O -Wall
。
如果使用strcpy
,还需要为文件名分配内存。在简单的程序中不需要这一步骤;如果您在从客户端继续阅读后需要记住文件名,那么制作副本会很有用。 strdup
函数将内存分配与字符串复制相结合,这在这里是合适的。
您需要检查所有系统调用的返回值。 read
的返回值告诉您读取了多少字节。如果操作系统感觉如此,则允许对read(fd,buf,n)
的调用返回少于n
个字节。如果您收到的字节数少于预期,请在循环中调用read
。是的,几乎所有调用read
的程序都在循环中调用它,这是一个基本的Unix / POSIX习惯用法。 fread
函数可以为您完成,如果您可以使用它。
缺少检查msg.code
和msg.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)
的返回值,它告诉您已经读取了多少字节, - 您的消息可能无法完整读取,因此文件名可能会被截断。
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特别有用 - 以前从未使用过它)