用QSocket来操作Linux命名管道

  今天使用QSocket来操作命名管道时出现了一些小插曲,调试花了一些时间,写下来作一个笔记:

  这里所说的命名管道是指FIFO,当打开一个FIFO的时候,通常会出现以下情况:
  a. 不使用O_NONBLOCK标志时,只读open要阻塞到某个其它进程为写而打开它为止
  b. 不使用O_NONBLOCK标志时,只写open要阻塞到某个其它进程为读而打开它为止
  c. 如果在open的时候指定O_NONBLOCK标志,当只读open时,没有进程为写而打开FIFO的话,会返回-1,只写open时,没有进程为读而打开FIFO的话也会返回-1表示失败。

  以上的情况使FIFO的使用带来了一些不便,但有一个常用的技巧是,只要用O_RDWR(读写)来打开一个管道,则不会返回失败,而open也不会阻塞。两个进程使用FIFO来进行通信时,通常会使用两个FIFO,一个用于发送数据(即进行写操作),一个用于接收数据(即进行读操作),而这两个FIFO需要均使用O_RDWR来打开。使用系统调用open, read, write来操作这两个FIFO没有什么问题,程序工作得很好,

  由于项目需要,管道的另一个读写端位于Qt上的一个应用程序,因此可以方便地使用QSocket来操作管道,
以写管道为例,  我使用了以下步骤:

  1. 先用O_RDWR标志用open系统调用打开管道,并得到一个fd
  2. new一个QSocket对象, 暂且命名为 pSocket
  3. 把fd赋给此QSocket对象, 调用 pSocket->setSocket( fd );
  4. 现在可以调用 pSocket->writeBlock 往管道中写数据了

  测试时发现, 只有第一个pSocket->writeBlock 调用往管道写数据时, 对端能收到, 其它的多次调用, 对端均收不到使用pSocket->writeBlock写的数据。

  难道是写一次后,某些状态被改变了才导致后面的写操作失败?  检查pSocket->writeBlock 的返回值,是正常的,返回了写数据的数目而非-1;再用pSocket->state()检查当前的状态,返回Connection,也是正常的啊;连接QSocket的bytesWritten信号,也能正常是返回写了多少字节。

  情况貌似一切正常啊,但对端就是收不到数据,可能是数据在缓冲区中没发出去?调用一下flush,于事无补,情况依旧,难道是对端的程序设计的有问题?作了个试验,不使用QSocket往FIFO写数据,改为使用系统调用write来写,结果一切正常,而以之前也有对对端作过测试的,所以排除了是对端程序设计有问题。

  回顾了一下整个过程,再看了一个QSocket的文档,QSocket是带缓冲的,也就是说,当我们用QSocket往FIFO写数据时,QSocket会先将你的数据缓冲起来,当FIFO有数据可读时,QSocket也会把数据接收并缓冲起来,等待我们去读取它...停,我们是用O_RDWR会打开FIFO的,会不会是当我们用QSocket往FIFO写数据时,紧接着QSocket自已又把它读走,而导致其它进程读不到数据了呢?

  赶紧connect信号readyRead看看,果然,在我们调用writeBlock后,紧接着readyRead被触发了,真相大白,是QSocket自已把数据又读走了。

  最后,解决的办法也很简单,当需要用QSocket用操作FIFO时,就不要用O_RDWR来打开FIFO, 而是,在打开读FIFO时使用只读打开,而打开写FIFO时使用只写打开,为了FIFO在其它进程没有就绪的情况下,open不至于阻塞,还需要加上_NONBLOCK标志。

-------------------------------------------------------------------------------------------------------------------------------------------------------
  转载请注明出处: http://www.tzsblog.com

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章