简体   繁体   中英

How to read a long from a pipe?

This concerns unnamed pipes in interprocess communication. I have a pipe and one process stores a value in it and the other want to read this valus which is numerical, either int or long.

It is well described here http://tldp.org/LDP/lpg/node11.html how to create pipes in C. My question is how to read a long or int from a pipe.

extract from above mentioned page:

/* Read in a string from the pipe */
int nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
printf("Received string: %s", readbuffer);

well, in generell i have no idea how a pipe is treated in C (It is like a file?) and how i can read data other than a string from it.

You can't "really" read a long from a pipe. You read a sequence of bytes from a pipe, and if you can define some protocol for which long those bytes represent, then you've read a long.

Assuming that both ends of the pipe are using the same storage representation for long , which they are if they were compiled with the same compiler for the same architecture, or for that matter with different compilers but using the same ABI, then you can write(fd, &src_long, sizeof(long)); at one end, and read(fd, &dst_long, sizeof(long)); at the other end. Plus or minus the usual messing about to ensure the I/O didn't finish early.

A pipe is just like a file, except it is unseekable. When you read data, it is "gone" from the pipe and can't be read again.

You would read a datastructure like you would from any other file. It can be done with scanf, fstream>> or with a read() and a union.

Since both ends of your pipe are on the same machine, you don't have to worry about differences in machine architectures; if you changed the question to discuss sockets, you would have to worry about that.

You can write a long to the pipe using:

long l = 0x01020304L
if (write(pipe_w_fd, &l, sizeof(l)) != sizeof(l))
    ...handle error...

And you can read the value off the pipe using:

long l;
if (read(pipe_r_fd, &l, sizeof(l)) != sizeof(l))
    ...handle error...

If you had to deal with different machine architectures, you'd format the value into a platform-neutral format (eg big-endian) and write that on one end, and read the platform-neutral data on the other end and convert back to the local machine-specific format.

Depends on how it's sent. If you have some protocol / framing convention, you'll have to read the frame and then extract the int. If you're sending just the int itself, you can read sizeof(int) bytes and then use the bytes in the buffer directly:

int foo = *((int*) readbuffer);

Since the pipe is local, you won't have to (in most cases) care about endianness and sizes here.

well, in generell i have no idea how a pipe is treated in C (It is like a file?)

Yes.

and how i can read data other than a string from it.

This is the naive case, which assumes the long is binary and the same size in the system. If the long was written as a string, read a string then find the long.

long mylong;
int nbytes = read(fd[0], &mylong, sizeof(long));

It is treated like a file. I would read up on scanf to see what data you can easily parse. Things like integers, and integers in hex or oct can be easily parsed, even pointers can be parsed. Longs are not as simple, but you can just parse a long from a string (%s) and store it in a long later.

http://beej.us/guide/bgc/output/html/multipage/scanf.html

You can do this:

long l;

if (read(fd[0], &l, sizeof(l)) != sizeof(l))
{
   /* TODO: handle this */
}

By having your serialization type be long you lose some flexibility here, as it may be possible that whoever is reading this data ends up with different byte order or a different size for long . Imagine, as an example, that you fork and dup2(fd[1], 1) t hen end up exec -ing an SSH command in the child process... Now the data potentially comes from another machine, and there will be problems. To avoid it you can do something like this:

/* Type of l has a predictable size. */
uint32_t l;

if (read(fd[0], &l, sizeof(l)) != sizeof(l))
{
   /* TODO: handle this */
}

/* Convert byte order of what we just read */
l = ntohl(l);

In actuality it's a little strange to read in 32-bit increments... What you should consider is to come up with a message format and read larger chunks of data at a time. A good way to accomplish this is for each quantity of information to have a header that indicates the size of what follows, message type, etc. Or if you don't find this appealing you can consider having your serialization be text. This would also provide a decent answer to the endianness problem.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM