无法同步FIFO上的阻塞读写

时间:2011-05-21 13:41:34

标签: c linux

我正在创建一个非常简单的程序,它由客户端使用的小API和服务器进程组成。客户端进程和服务器进程通过一对FIFO进行通信(一个用于对服务器的请求,另一个用于来自服务器的响应)。

  • 服务器继续使用阻塞读取(O_RDWR标志)
  • 读取请求FIFO
  • 客户端在请求FIFO(O_WRONLY标志)
  • 上写入请求
  • 服务器读取请求,它对它起作用并在响应FIFO上写入响应(O_WRONLY标志)
  • 客户端读取响应(O_RDONLY标志):如果服务器没有通信任何数据(我的意思是未定义的长缓冲区),那么写入FIFO的响应就足够了,工作就完成了
  • 其他......
  • 客户端读取服务器将要发送数据的响应,因此它再次打开响应FIFO(O_RDONLY标志)
  • 服务器使用(O_WRONLY标志)
  • 写入数据

最后一次写入似乎没有阻止服务器进程,直到客户端在另一端读取:为什么?我错过了什么? 为了实现我的目标,我必须在写入调用之前放置一个sleep(1),但这仅适用于对服务器的某种请求:我如何帮助您帮助我?

服务器代码

                /* until here everything is ok: client read the response and waits for the buffer */
                sleep(1);
                /* open the FIFO and send the buffer */
                if((fifofrom = open(FIFOFROMMMBOXD, O_WRONLY)) == -1)   logMmboxd("error in opening FIFOFROM again for the buffer\n", 1);
                else                                                    logMmboxd("opened FIFOFROM again for the buffer\n", 0);

                if((write(fifofrom, mails, sizeof(mmbox_mail_complete)*m)) != sizeof(mmbox_mail_complete)*m)   logMmboxd("error in writing FIFOFROM again for the buffer\n", 1);
                else                                                                                           logMmboxd("written on FIFOFROM again for the buffer\n", 0);      
                close(fifofrom); 

                logMmboxd("messages list definitely sent\n", 0);

客户代码

void lockUp(Request *request, Response *response, void **buffer)
{
int fifofrom, fifoto, lock;     

/* lockto access the FIFOs */
if((lock = open(LOCK, O_RDONLY)) == -1)   logMmboxman("error in opening LOCK\n", 1);
else                                      logMmboxman("opened LOCK\n", 0);

if(flock(lock, LOCK_EX) == -1)            logMmboxman("error in acquiring LOCK\n", 1);              
else                                      logMmboxman("acquired LOCK\n", 0);  

/* open the FIFO and write the request */
if((fifoto = open(FIFOTOMMBOXD, O_WRONLY)) == -1)   logMmboxman("error in opening FIFOTO\n", 1); 
else                                                logMmboxman("opened FIFOTO\n", 0);  

if((write(fifoto, request, sizeof(Request))) != sizeof(Request))   logMmboxman("error in writing FIFOTO\n", 1);
else                                                               logMmboxman("written on FIFOTO\n", 0);
close(fifoto);

/* waiting for response on FIFOFROM */
if((fifofrom = open(FIFOFROMMMBOXD, O_RDONLY)) == -1)   logMmboxman("error in opening FIFOFROM\n", 1);
else                                                    logMmboxman("opened FIFOFROM\n", 0);

if((read(fifofrom, response, sizeof(Response))) != sizeof(Response))   logMmboxman("error in reading FIFOFROM\n", 1);
else                                                                   logMmboxman("read from FIFOFROM\n", 0);
close(fifofrom);

/* if size>0 then the server has to send a buffer of data to me! */
if(response->size)
{
    if((fifofrom = open(FIFOFROMMMBOXD, O_RDONLY)) == -1)   logMmboxman("error in opening FIFOFROM again for the buffer\n", 1);
    else                                                    logMmboxman("opened FIFOFROM again for the buffer\n", 0);

    *buffer = (void*)malloc(response->size);

    if(read(fifofrom, *buffer, response->size) != response->size)   logMmboxman("error in reading FIFOFROM again for the buffer\n", 1);
    else                                                            logMmboxman("read from FIFOFROM again for the buffer\n", 0);
    close(fifofrom);    
}

/* read the response: I release the lock */
if(flock(lock, LOCK_UN) == -1)            logMmboxman("error in releasing LOCK\n", 1);              
else                                      logMmboxman("released LOCK\n", 0);  

return;
}

1 个答案:

答案 0 :(得分:0)

所以(1)关于FIFO同步的理由是正确的; (2)linux几乎没有机会搞砸了;所以(3)你有一个错误。

很难说但是因为你最初打开服务器fifo作为O_RDWR,也许你没有关闭你的想法?也许你有第二个运行的客户端已经将fifo作为读者打开,当你以O_WRONLY重新打开时它不会阻塞?

无论如何,您真正的问题是您设计的协议。你不需要我可以看到需要锁或保持打开和关闭fifos。你需要一个明智的沟通协议。

通常情况如下:

(1)服务器有一个众所周知的fifo客户端打开并写入。

(2)客户传递交易代码或表明这是初始请求的事情。包括服务器建立连接回客户端的一些方法。这可能是一个完整的路径名,或者只是一个客户端和服务器使用预定的路径创建第二个fifo的pid(例如,打开“/ tmp / myfifo_pid”或其他一些)。

(3)客户&服务器打开第二个fifo,对服务器的所有进一步客户端请求包括pid(或其他),以便服务器知道输出请求的位置。

(4)完成所有操作后,客户端发送一个指示这样的事务,以便服务器可以关闭第二个fifo。客户也这样做。

(5)重复许多客户。

请注意,您需要指定邮件的格式。历史悠久的技术是使用长度代码(似乎是你正在尝试的)或某种msg结束分隔符(例如换行符)。

修改

可能的邮件格式:

长度| TRANCODE ||数据|

其中length表示整个消息包含多少个后续字节,转码指定和操作(例如打开我的输出fifo,关闭它,发送数据等等),数据是适合该事务的任何内容。