0

I'm writing Client-Server application using posix FIFO to communicate. Both client and server are single thread and single process application.

The server is design to handle multiple clients. Each client has own pair of named pipe, one to send messages from Server to this Client and the other to send messages from Client to the Server.

The idea is quite simple, Server loops through all Client to Server pipes and check if there is something to read there.

My first implemenentation was sth like:

/* SERVER */
int desc = open(pipeName, O_RDONLY | O_NDELAY); //1
assert(desc > 0); //just simplyfing error handling
int read = read(desc, buffer, BUFSIZE); //2
if(read > 0)
  do_stuff();
close(desc); //3

/* CLIENT */
int desc = open(pipeName, O_WRONLY) //4
assert(desc > 0); //just simplyfing error handling
int read = write(desc, buffer, BUFSIZE) //5
close(desc); //6

As far as I know this code is invalid.

There are race conditions and for example an order of calls like: 1, 2, 4, 3, 5, 6 - will probably cause SIGPIPE.

The problem is that nonblocking read open is always successful even if there is no writer on the other side of PIPE. That means that if Client will block on open() then server do nonblocking open (which will unlock Client) and then read() which will return 0 because at the moment nothing will be in PIPE and close() afterwards, then when control will go back to client which want to do write() on opened PIPE it will cause SIGPIPE as the reader is no longer available (server already closed the pipe).

For now i see two solutions:

  1. Handle SIGPIPE in Client with "tryAgain()" - this looks really bad, if i do such thing there is no guarantee that it will work at any moment - it will depend on possibility of good command processing order...
  2. Keep reading PIPE open all the time in Server (open it once and close when connection will be considered finished) - it is inconvenient in my application architecture but of course possible. I guess it will fix the problem but I'm not sure about that.

Here are my questions:

  1. Is any of those two approaches correct way to do that?
  2. Is there any other way to handle that scenario?
  3. Do you think second solution will work correctly?
  4. What would you choose and why?

Thanks for every answer.

xaxxon
  • 19,189
  • 5
  • 50
  • 80
Yester
  • 652
  • 6
  • 18
  • 1
    OT: It should be `assert(desc != -1);` or `assert(desc >= 0);` as `open()` returns `-1` on error or a non-negative integer on success. – alk May 26 '13 at 08:28
  • don't edit the posters question/code. Either comment or answer about how it's wrong. – xaxxon May 26 '13 at 08:33
  • When you say it's supposed to handle multiple clients, do you mean simultaneously? Because your code only handles one at a time. No changes that handle sigpipe or "reading pipe open all the time in server" is going to make it handle multiple connections simultaneously. – xaxxon May 26 '13 at 08:36
  • Well, not simultaneously, but i want it to make such impression. I mean - it can loop through all clients and always handle one thats ready ASAP. – Yester May 26 '13 at 08:42
  • And sorry for that edit. You're right. – Yester May 26 '13 at 08:44
  • haha, actually I didn't realize it was YOUR edit. That is fine and if you want to change it, that's fine. I thought someone else did it, but I wasn't paying attention. – xaxxon May 26 '13 at 09:01
  • Hey @xaxxon, the edit-log clearly shows how did the edit, doesn't it? ;-) – alk May 26 '13 at 09:20
  • yes, it does. Hence "not paying attention" – xaxxon May 26 '13 at 09:20

1 Answers1

2

I'm having a lot of trouble understanding your question. Things

Client will block on open() <== nothing blocks on open

Use select or epoll to determine which file descriptors are readable and writeable.

Then, just call read on those.

You will be notified that the client closed the pipe as a read event you'll need to handle and not write if it is closed.

http://linux.die.net/man/4/epoll

https://banu.com/blog/2/how-to-use-epoll-a-complete-example-in-c/

xaxxon
  • 19,189
  • 5
  • 50
  • 80
  • Server can poll to find which of clients wants to write something and probably it will kind of work (i mean it will find out that some of pipes are being opened by clients for write and are waiting for reader to start writing to those pipse). But I'm not sure if it will change the problem. Still if server will find that there is client that want to write something and it will open and then read with NODELAY flag it will cause it to read 0 bytes and then close (server cannot wait for data as it's one thread only!). – Yester May 26 '13 at 08:42
  • That means client will have sam problem - its open instruction will be unlocked but when process reaches write there will be no reader on the other side (already closed) and it will cause SIGPIPE. Or am I wrong? – Yester May 26 '13 at 08:43
  • you are wrong, because if you're correctly polling, you will be notified that the other side has terminated the connection so you can know not to call write on it. – xaxxon May 26 '13 at 09:01
  • Hm, then I will try to implement it that way today. I suppose there might be some problem with system notifications handling in my C++ OO code, but i guess nothing impossible to handle - it will just look awfully ;) Thanks for that answer. – Yester May 26 '13 at 09:07