【问题标题】:What to do when the client connects, but does not send data?客户端连接但不发送数据怎么办?
【发布时间】:2021-02-15 20:22:23
【问题描述】:

我正在用 C 语言编写自己的 Web 服务器。但我遇到了一个烦人的问题。 我正在等待这样的传入连接:

struct sockaddr_in caddr;
uint32_t caddr_len = sizeof(caddr);
int fd = accept(sfd, (struct sockaddr *)&caddr, &caddr_len);
if(fd < 0) {
  err(EXIT_FAILURE, "accept()");
}

当accept() 成功时,我开始接收数据:

errno = 0;
ssize_t r = recv(fd, buf, sizeof(buf), 0);

有时在使用 Firefox 访问时,我没有收到任何数据。 当我将超时设置为 1s 时,errno 设置为 EAGAIN。 当我将超时设置为 5s 时,errno 将不会设置,但我仍然没有收到任何数据r == 0。

是否可以配置套接字,使accept() 仅在有实际数据可用时返回?

注意:我在使用 Chrome 访问时没有遇到这种情况。

编辑:有人建议我应该使用poll()

当我使用poll()时,我遇到了同样的问题:

struct pollfd p[] = {{sfd, POLLIN}};
int r = poll(sfd, 1, 1000);
if(r <= 0) err("poll() -> %d", r);

r == 1,但我仍然有同样的问题,因为这个poll() 只适用于监听套接字。接受时它并没有告诉我是否有实际的有效载荷。

【问题讨论】:

  • 我找到了解决方案。 poll() 可以同时观察多个fds。所以我使用第一个条目作为监听 fd (sfd)。如果有一些变化,我会打电话给fd = accept(sfd) 并将新的fd 放入同一个监视列表中。当其中一个新创建的fds发生变化时,我就知道这个fd有数据了。
  • 不清楚您如何将超时设置为....,以及您如何知道发生了超时。这就是我们要求Minimal, complete and verifiable 示例的原因。请参阅之前引用的页面,并使用如此完整且可验证的示例编辑您的问题。

标签: c linux sockets


【解决方案1】:

当连接被接受时,Accept 返回。如果您想等到有数据可供读取,则需要使用poll 或select(或阻塞read)。

【讨论】:

  • 当我使用 poll() 时,我遇到了同样的问题,因为它告诉我的只是,有一个客户端想要连接。我需要的是:(想要连接并且有有效负载)
  • @Cosinus 将新连接的fd 添加到poll/select 参数并再次等待。
  • @alagner 这就是我要避免的,因为 Firefox 会阻止我的运行器,直到超时发生。与此同时,这个跑步者可能已经处理了来自其他客户的多个请求。
  • @Cosinus 不知道您如何准确地处理多个客户端,但底线是:连接和发送是两个不同的操作。您可以在所有连接的客户端上select/poll/put-your-async-call-here 并仅处理当前正在发送的客户端。另一种选择是使用多线程/多处理服务器。但这一切都取决于你到底在做什么。
  • @Cosinus:你想要的是不可能的,因为客户端是否要连接是监听套接字的属性,而有效负载是否可供读取是已经连接的套接字的属性。在您调用 accept 并且它返回之前,连接的套接字不存在。要执行您所要求的操作,需要向内核添加另一个系统调用,以便能够查询在尚无套接字的未接受连接上是否有可用数据。
【解决方案2】:

您可以使用select、poll 或类似名称。看: https://stackoverflow.com/a/12862015/4885321

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多