首页 > 解决方案 > 读取某些内容后立即返回 ReadFile()

问题描述

我想在 Linux 和 Windows 上以一致的方式从串口读取数据。我注意到了这一点,read()并且ReadFile()表现得有些不同。考虑以下代码:

// on Linux
int r = read(fd, buf, 256);

// on Windows
ReadFile(handle, buf, 256, &r, NULL);

这两个函数都将永远阻塞,直到数据到达。到目前为止,一切都很好。但是,有一点区别:read()至少 1 个字节到达时将返回,而ReadFile()在所有 256 个字节到达之前不会返回。

因此,我想问:有没有办法让ReadFile()行为像read()在 Linux 上一样,即即使请求了 256,只要至少有 1 个字节就返回?

标签: cwinapiserial-port

解决方案


IMO 最好的方法是实现循环缓冲区,使用您喜欢的函数从缓冲区中的流位置读取 1 个字节,然后调用接收回调函数 - 或者只是轮询循环缓冲区以获取数据存在。

它解决了您的所有问题 - 当数据到达并且不会覆盖缓冲区时,您将收到通知(或者您可以轮询存在的数据)(当然您需要读取数据,否则如果缓冲区已满,您将忽略新数据)

这里有一个非常简单的实现

unsigned char buff[128];

struct 
{
    unsigned head:8;
    unsigned tail:8;
}control = {.head = 0, .tail = 0};

int isFull(void)
{
    return (control.head + 1) == control.tail;
}

int isEmpty()
{
    return control.head == control.tail;    
}

int push(int ch)
{
    if(!isFull())
    {
        buff[control.head++] = ch;
        return 0;
    }
    return -1;
}

int pop(void)
{
    if(!isEmpty())
    {
        return buff[control.tail++];
    }
    return -1;
}

并且使用简单

void (*rcvcallback)(void);
initReceive(void (*callback)(void))
{
    rcvcallback = callback;
}

void receive(void)
{
    int r = 0;

    #ifdef LINUX
    read(fd, &r, 1);
    #endif

    #ifdef WINDOWS
    size_t size;
    ReadFile(handle, &r, 1, &size, NULL);
    #endif

    push(r);
    rcvcallback();
}

#ifdef WINDOWS
#define EL "\n\r"
#endif
#ifdef LINUX
#define EL "\n"
#endif


void myRCVcallback(void)
{
    printf("Byte received: %d"EL, pop());
}


int main()
{
    printf("Starting ......"EL);

    while(1)
    {
        receive();
    }

    return 0;
}

推荐阅读