I'm writing a simple text-based protocol interpreter for server. The server will receive a response in the format of METHOD [filename]\\n[file_size][data]
from socket, where the string length of METHOD
, filename
, and data
vary. file_size
is the number of bytes of data
. Since the length of METHOD
and filename
vary, I try to use fscanf()
to capture them. After that, I use read()
to get file_size
and data
. However, the problem is read()
never prints. I wrote a small case to illustrate my problem:
#define MSGSIZE 16
char* msg1 = "hello world\n#1";
int main()
{
char inbuf[MSGSIZE], *buf_1, *buf_2;
int p[2], i;
if (pipe(p) < 0)
exit(1);
write(p[1], msg1, MSGSIZE);
FILE *fd = fdopen(p[0], "r");
fscanf(fd, "%ms %ms\n", &buf_1, &buf_2);
printf("buf_1: %s, buf_2: %s\n", buf_1, buf_2);
// read never prints
read(fileno(fd), inbuf, 3);
printf("buf: %s\n", inbuf);
return 0;
}
I would expect fscanf()
to move the character pointer to '#' in "hello world\\n#1", then read should be able to print out following characters, which didn't happen. I'm a bit confused because if I call fscanf()
instead of read, it would print. Is this because fscanf()
manipulates file indicator differently from read()
?
You should not mix operations on the FILE * with operations on the underlying file descriptor. If you just replace read
with an fread
, it should behave as you expect. The fscanf
(probably, almost certainly) reads everything from the pipe and stores it in an internal buffer, so your read
has no data left to consume. To access the internal buffer, use fread
or fgetc
or fgets
, but don't try to work on the underlying file descriptor.
Mixing FILE* stream I/O with system calls on the underlying file descriptor is the problem. Here is a change I made that shows one way to avoid it in your code.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define MSGSIZE 16
char* msg1 = "hello world\n#1\n";
int main()
{
char inbuf[MSGSIZE], *buf_1, *buf_2;
int p[2], i;
if (pipe(p) < 0)
exit(1);
write(p[1], msg1, MSGSIZE);
FILE *fd = fdopen(p[0], "r");
fscanf(fd, "%ms %ms\n", &buf_1, &buf_2);
printf("buf_1: %s, buf_2: %s\n", buf_1, buf_2);
// read never prints
//retVal = read(fileno(fd), inbuf, 3);
// replace read() with fgets()
if(fgets(inbuf, sizeof(inbuf), fd) == NULL)
{
printf("Error with fgets()\n");
}
else
{
printf("buf: %s\n", inbuf);
}
return 0;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.