我正在Objective-C中编写一个串行通信包装器类。要列出所有可用的串行调制解调器并设置连接,我使用的代码与this example project by Apple中使用的代码几乎相同。
我可以读写苹果做的方式。但我想在第二个线程上实现一个循环,如果NSString *writeString
长0则写入流,如果字节可用,则写入后读取。
我的写作非常直接。我刚刚使用了write
中声明的unistd.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);
我在这里做错了什么?
答案 0 :(得分:1)
read
()会阻止。 Apple可能有自己的做法,但您可以使用select
()查看_fileDescriptor
上是否有任何内容可供阅读。谷歌周围有关如何使用选择的例子。
这是StackOverflow上的一个链接:
Can someone give me an example of how select() is alerted to an fd becoming "ready"
选择人的摘录属于:
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().
答案 1 :(得分:0)
您可以使用O_NONBLOCK
在文件描述符上设置非阻塞标记(fcntl()
),以防止read()
等待数据,但如果您这样做,则必须持续民意调查寻找数据,这从CPU使用的角度来看显然是不好的。正如Charlie Burns的回答所解释的那样,最好的解决方案是使用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
这样做。