【问题标题】:System-call read() blocked系统调用 read() 被阻塞
【发布时间】:2020-11-11 02:42:48
【问题描述】:

我有一个客户端需要在套接字上读取服务器发送的一系列字符。 客户端使用系统调用 read() 读取套接字 SOCK_DGRAM。

这里是完整的函数,里面有系统调用 read(..)。

ssize_t readLine(int sockd, void *vptr, size_t maxlen)
{
    ssize_t n, rc;
    char    c, *buffer;
    buffer = vptr;

    for ( n = 1; n < maxlen; n++ ) 
    {

        rc = read(sockd, &c, 1);
        if ( rc == 1 ) 
        {
            *buffer++ = c;
            if (c == '\0') break;
        }
        else
        {
                if (errno == EINTR) continue;
                return -1;
        }
    }
    *buffer = 0;
    return n;
}

问题是,如果服务器发送一个像 ABCDEF'\0' 这样的字符序列,这个客户端只读取 A,然后系统调用 read() 进入阻塞模式。 我已经使用 Wireshark 来查看服务器是否运行良好,并且它在 UDP 数据包中正确发送了 ABCDEF'\0'。从这个角度来看一切都很好。

在此先感谢大家。

【问题讨论】:

  • 你需要一次读取整个数据报
  • 如何知道数据报的维度?每次都不一样。
  • @ABC 这是你的协议——你决定每个数据报包含什么——所以你可以决定最大值。您指定可以收到多少,预先设定的最大值。如果发送的更少,您将获得更少。 recv/read 会告诉你收到了多少。
  • 如果我阅读的内容多于发送的内容会怎样?
  • 一次读取的字节数不能超过数据报的大小。

标签: c sockets unix system-calls


【解决方案1】:

使用数据报套接字,您需要一次读取和写入整个数据报。

如果您没有给read 足够的空间来读取整个数据报,那么数据报的其余部分就会消失。

int datagram_length = read(sockd, vptr, maxlen - 1);
if (datagram_length < 0) {
    // complain about the error
} else {
    vptr[datagram_length] = 0;
}

【讨论】:

  • 非常感谢您的回答。为什么会这样?
  • @ABC 就是这样。你认为它是如何工作的?数据报不同于流。
  • 我认为它像 TCP 一样工作,我可以逐个读取字节并将它们放入缓冲区中。为什么会有这样的设计选择来阻止阅读,就好像它是一个流程一样?
  • @ABC 一个流套接字就是一个流。数据报套接字不是。你要求让它不像流。
  • @ABC 如果将数据报视为流,您如何知道每条消息的开始和结束位置?这个问题存在于 TCP 中,并且必须由每个应用程序协议通过手动分隔每个消息来解决。但在 UDP 中不存在这个问题,因为数据报是自包含的,不必由应用程序分隔。
猜你喜欢
  • 1970-01-01
  • 2012-11-17
  • 2023-03-09
  • 1970-01-01
  • 1970-01-01
  • 2014-07-15
  • 2015-05-24
  • 2013-10-19
  • 1970-01-01
相关资源
最近更新 更多