1

我正在用 Objective-C 编写一个串行通信包装类。为了列出所有可用的串行调制解调器并设置连接,我使用的代码与Apple 在此示例项目中使用的代码几乎相同。

我可以像苹果那样读写。但是我想在第二个线程上实现一个循环,如果NSString *writeString更长的 0 则写入流,如果字节可用,则在写入后读取。

我的写作工作非常简单。我只是使用了writeunistd.h.

阅读将不起作用。每当我调用read()时,函数都会挂起,并且我的循环不会继续。

这是我的循环中使用的代码:

- (void)runInCOMLoop {
    do {
        // write
    } while (bytesWritten < strlen([_writeString UTF8String]));

    NSMutableString *readString = [NSMutableString string];
    ssize_t bytesRead = 0;
    ssize_t readB = 0;
    char buffer[256];

    do {
        readB = read(_fileDescriptor, &buffer, sizeof(buffer));
//              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this function hangs
        bytesRead += readB;

        if (readB == -1 {
            // error
        }
        else if (readB > 0) {
            if(buffer[bytesRead - 1] == '\r' ]] buffer[bytesRead - 1] == '\n') {
                break;
            }

            [readString appendString:[NSString stringWithUTF8String:buffer]];
        }
    } while (readB > 0);

我在这里做错了什么?

4

2 回答 2

1

read() 如果没有可读取的内容,将阻塞。Apple 可能有自己的处事,但你可以使用select() 来查看是否有什么可以阅读的_fileDescriptor。谷歌搜索有关如何使用 select 的示例。

这是 StackOverflow 上的一个链接:

有人可以给我一个例子,说明 select() 如何提醒 fd 变得“准备好”

选择人的摘录与以下内容有关:

     To effect a poll, the timeout argument should be
     non-nil, pointing to a zero-valued timeval structure.  Timeout is not
     changed by select(), and may be reused on subsequent calls, however it is
     good style to re-initialize it before each invocation of select().
于 2013-11-14T16:17:10.220 回答
0

O_NONBLOCK您可以在文件描述符上设置fcntl()非阻塞标志(read()正如查理伯恩斯的回答所解释的那样,最好的解决方案是使用select()它将允许您的程序有效地等待,直到端口的文件描述符上有一些数据要读取。下面是一些示例代码,取自我自己的 Objective-C 串口类ORSSerialPort(稍作修改):

fd_set localReadFDSet;
FD_ZERO(&localReadFDSet);
FD_SET(self.fileDescriptor, &localReadFDSet);

timeout.tv_sec = 0; 
timeout.tv_usec = 100000; // Check to see if port closed every 100ms

result = select(localPortFD+1, &localReadFDSet, NULL, NULL, &timeout);
if (!self.isOpen) break; // Port closed while select call was waiting
if (result < 0) {
    // Handle error
}

if (result == 0 || !FD_ISSET(localPortFD, &localReadFDSet)) continue;

// Data is available
char buf[1024];
long lengthRead = read(localPortFD, buf, sizeof(buf));
NSData *readData = nil;
if (lengthRead>0) readData = [NSData dataWithBytes:buf length:lengthRead];

请注意,select()表示数据可通过返回获得。select()因此,当没有可用数据时,您的程序将在通话中暂停。该程序没有挂起,这就是它应该如何工作。如果您在等待时需要做其他事情select(),您应该将select()调用放在与您需要做的其他工作不同的队列/线程上。ORSSerialPort做这个。

于 2013-11-15T19:50:03.923 回答