nickst97
nickst97

Reputation: 23

C: Read from pipe char AND int, simultaneously (tricky one)

I am writing in a pipe some integers and when I am ending I write "11". Then, when I am reading from the same pipe, I have to take the integers and do stuff with them and when I get the "11", I should terminate. But I cannon think of any solutions to read simultaneously in the pipe for int and char (I know that is working based on a fifo method).

Any ideas?

//THIS IS AN EXAMPLE CODE OF WHAT I WANT TO DO 

//I am writing to the pipe
while(CONDITION)
    write(mypipe, &random_int, sizeof(short));
write(mypipe, "1", sizeof("11"));

/* code... */

//I am reading from the pipe
while(TRUE){
    read(mypipe, &received_int, sizeof(short));
    // if strcmp(receiver_int, "11")==0 then exit;
    // else do stuff with receiver_int
}

Upvotes: 0

Views: 771

Answers (2)

John Bollinger
John Bollinger

Reputation: 180266

I cannon [sic] think of any solutions to read simultaneously in the pipe for int and char

There aren't any solutions to that problem per se, because one reads neither characters nor integers from a pipe, but rather raw bytes. Everything else is about how the bytes are interpreted.

(I know that is working based on a fifo method).

FIFOs have exactly the same constraints as pipes.

Generally speaking, if you want to pass objects of different types across any communications medium, you need some kind of format or protocol that enables the receiver to interpret the data as the sender intended. That can range from very simple to very complex. What you describe is an especially simple protocol (too simple, really): the data consist of byte pairs, with each pair interpreted as the bytes of an unsigned integer, except that there is a special two-byte sequence that marks the end of the data.

For such a protocol, I might write the receiving side something like this:

union {
    uint16_t num;
    char s[3];    // Three bytes, not two, to allow for a terminator
} buffer = { .s = { 0 }};

while (1){
    read(mypipe, &buffer, sizeof(uint16_t));
    if (strcmp(buffer.s, "11") == 0) {
        break;
    }
    // do stuff with buffer.num ...
}

But no, the protocol as you describe it does not provide a way to distinguish the two bytes of "11" from the same two bytes used as an integer value. As a result, there is one integer value that cannot be sent via this protocol. Quite possibly it is 12593 (decimal), which would result from encoding the characters of "11" in ASCII and then reinterpreting the result as a two-byte integer.

Upvotes: 0

Fire Lancer
Fire Lancer

Reputation: 30145

A pipe is just a byte stream, even if you interpreted the read bytes correctly as a 16bit integer and as a 2 character string "11" which in ASCII is the bytes 31 31, then how do you tell "11" apart from the integer 12593? They have the same binary representation.

One option is to just keep reading until the pipe is terminated, this may be suitable say for transferring a file. But does not allow on-going back and forth messages.

write(mypipe, &random_int, sizeof(short));
close(mypipe); // finished writing

// recv
while (true)
{
    short received_int;
    if (read(mypipe, &received_int, sizeof(short)) == sizeof(short)) // Not handling the int getting split into two separate read's here
    {
        // Use received_int
    }
    else return; // 0 on close
}

This is why most protocols introduce the concept of messages on top of the stream (either in text or binary). For example you might have an 8bit "opcode" and say that 0 is "disconnect" and 1 is "message with integer", so to write an integer:

 unsigned char opcode = 1;
 short random_int = 55; // Make sure it actually a short, as you used sizeof(short)!
 write(mypipe, &opcode, 1);
 write(mypipe, &random_int, sizeof(short));

And to read you read the opcode first and then decide:

char opcode;
read(mypipe, &opcode, 1); // CHECK RETURN!
switch (opcode)
{
case 0: return; // Finished
case 1:
    {
        short received_int;
        read(mypipe, &received_int, sizeof(short)); // CHECK RETURN!
        // Use received_int
        break;
    }
}

You might look at some existing protocols on how they encode different things into the byte stream.

Upvotes: 1

Related Questions