0

Having in mind to communicate with a multi-client Unix domain socket without keyboard input, I want to create a file descriptor that replaces stdin.

With a multi-client socket, you have to add the stdin's file descriptor (which is 0, with FD_SET(0, &readfds)) to readfds in order to send the keyboard input (FD_ISSET(0, &readfds)) to the server. Since I don't want to write everytime I launch my client, I want to replace this file descriptor by a custom one (by writing to this file from another program).

I checked out Create a file descriptor to create two programs:

One that writes to the file descriptor:

int main() {
    char buffer[] = "test";
    int fd = open("sample.dat", O_WRONLY | O_CREAT, 0666);
    dup2(fd, 5);

    if(write(5, buffer, 4) < 0)
        fprintf(stderr, "write %s\n", strerror(errno));

    close(5);    
    return 0;
}

And another one that reads from it:

int main() {
    char buffer[4];
    int fd = open("sample.dat", O_RDONLY);
    dup2(fd, 5);

    for(;;) {
        if(read(5, buffer, 4) < 0)
            fprintf(stderr, "read %s\n", strerror(errno));

        printf("%s\n", buffer);
        sleep(1);
    }

    return 0;
}

My question is: is it possible to make this file descriptor as stdin-like ? I mean actually my second program read "test" endlessly because (of course) sample.dat still contains "test" but I want to delete it once it has been read.

Community
  • 1
  • 1
Raphaël
  • 117
  • 1
  • 1
  • 10
  • It's not very clear what you're asking - what do you mean by "stdin-like"? – Chris Turner Mar 15 '17 at 11:52
  • @ChrisTurner when you read something from stdin you read it only once, not endlessly because stdin "deletes"/"cleans" it (I don't know exactly how it works) once it has been read – Raphaël Mar 15 '17 at 12:18

3 Answers3

0

Yes. You can use pipes for this: https://linux.die.net/man/2/pipe

Or FIFOs: https://linux.die.net/man/3/mkfifo Using FIFOs will create a file in the filesystem which can be opened by the client and server process to communicate through.

dmi
  • 1,424
  • 1
  • 9
  • 9
0

If I understood correctly, you want to communicate to a program who can only read on the stdin. You have two ways to write in the stdin : the first way is to use your keyboard, and the second way is to use write().

#include <unistd.h>
#include <string.h>

int         main(void)
{
    char    *s = "what you want to write";
    write(STDIN_FILENO, s, strlen(s));
    return (0);
}

This program will write on the stdin, in the same way you would write with your keyboard. Besides, you will see the string printed on your command-line interface.

tfontain
  • 66
  • 12
  • I already tried to replace it by `write` but it appears `FD_ISSET` (http://man7.org/linux/man-pages/man2/select.2.html) doesn't accept it – Raphaël Mar 15 '17 at 13:00
  • You mean doing FD_ISSET(0, set) ? – tfontain Mar 15 '17 at 13:23
  • yes but by replacing the 0 (because I don't want keyboard input) by anything else (like another file descriptor) – Raphaël Mar 15 '17 at 13:26
  • Using stdin don't mean you forced to use your keyboard ; you can simply write into it with the function write() like I showed. But if by "keyboard input" you mean "standard input" - so you don't want to use the stdin - you should create a filedescriptor by opening an existing file or by creating a file. If you wants this file to have the same behavior than the stdin, you should look at lseek function, with SEEK_END to place the offset at the end and to read in this location. – tfontain Mar 15 '17 at 13:36
  • I tried to write like that but `FD_ISSET()` doesn't work, even with a custom file descriptor. Thank for lseek, I'm going to check it – Raphaël Mar 15 '17 at 14:32
0

The problem isn't that you're reading in "test" constantly, it's that you're not handling the call to read() properly. Whilst you're checking that it's not returning an error, you're not seeing how many bytes have been read in. read() doesn't null-terminate the string read in, so you should actually store the return value and use that to put the NUL in your buffer. Otherwise, since nothing in the buffer is changing, it'll appear as if you're re-reading the same text over and over.

    int err=read(fd, buffer, 4);
    if(err < 0)
        {
        fprintf(stderr, "read %s\n", strerror(errno));
        }
    else
        {
        buffer[err]='\0';
        }

If you make this change, you'll find that you only ever read in "test" once and after that you're not reading anything more in.

Note: You don't need the calls to dup2() - that's just for copying a file descriptor to known value. You can just use fd as is in your calls to read/write data.

Chris Turner
  • 8,082
  • 1
  • 14
  • 18
  • Ho yes it works thank you, it doesn't read "test" for ever but .. when I update the fd by writing "tess" in, it keeps reading anything. It only reads "tess" if I `CTRL+C` and relaunch it – Raphaël Mar 15 '17 at 14:05