【问题标题】:C Non-Blocking UDP SocketC 非阻塞 UDP 套接字
【发布时间】:2017-05-21 01:05:06
【问题描述】:

我一直在四处寻找如何让客户端在不阻塞主循环的情况下接收来自服务器的请求,我很抱歉,如果那里有重复,但我在网上找到的只是 TCP 版本,它不不适合我的目的 (UDP)。

现在服务器只是一个 Echo 服务器,所以我不在乎它是否阻塞。

服务器创建如下

ServerInstance Init(ServerConfiguration c) {
  ServerInstance n;
  n.endpoint = socket(PF_INET, SOCK_DGRAM, 0);
  Exitif(n.endpoint < 0, "Error opening endpoint socket");
  setsockopt(n.endpoint, SOL_SOCKET, SO_REUSEADDR, (const void *) &c.trueval, sizeof(int));
  setzero((char *) &n.servaddr, sizeof(n.servaddr));
  n.servaddr.sin_family = AF_INET;
  n.servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  n.servaddr.sin_port = htons(c.portno);
  Exitif(bind(n.endpoint, (struct sockaddr *) &n.servaddr, sizeof(n.servaddr)) < 0,
  "Error on binding socket to addr");
  n.buf = calloc(c.buffersize, sizeof(char))
  return n;
}

至于客户:

  connection = socket(AF_INET, SOCK_DGRAM, 0);
  IfThenExit(socket < 0, "Error initializing UDP socket\n");
  setzero((char *) &servaddr, sizeof(servaddr));
  servaddr.sin_family = AF_INET;
  servaddr.sin_port = htons(PORT);
  IfThenExit(inet_aton(SRVADDR, &servaddr.sin_addr) == 0, "IPV4 Address Invalid\n");
  CleanQueueAdd(&connection, Socket);

它像上面那样循环,我也有 SDL 的事件池,我想知道如何在不阻塞程序的情况下实现类似的东西

if(1) {
  while(SDL_PollEvent(&e)) {
    switch(e.type) {
      case SDL_QUIT:
        quit = 1;
        break;
      case SDL_KEYDOWN:
        quit = 1;
        break;
    }
  }
  // Recv here blocks ...
  // recv(...)
}

感谢您的阅读,祝您有愉快的一天

【问题讨论】:

  • 套接字引用的网络连接使用的协议对您如何设置套接字非阻塞和使用它没有影响。套接字接口独立于网络协议。
  • 您有两个选择。我希望看到 1/ 将套接字模式设置为非阻塞的代码,或者 2/ 使用选项调用套接字函数来指定非阻塞调用......但是我没有看到这两个......所以我投票关闭。
  • @Seb 我提出这个问题后将套接字设置为非阻塞模式,但与轮询或选择相比,这是最优的吗?我读到它浪费了 CPU 周期
  • @Whiteclaws 1/ What is premature optimisation? 2/ 不。无论如何,调用recv 是必要的,不是吗?无论如何,你最终都会打电话给他们,不是吗?循环完成后,为每个 非阻塞 套接字调用 recv,使用 sleep(0) 强制进行上下文切换,让操作系统有机会将更多数据放入队列并... 不浪费 ;) 此外,pollselect 并非完全非阻塞,并且您还没有向我们展示该代码这个问题没有任何非阻塞

标签: c sockets udp


【解决方案1】:

似乎 SDL 事件不能与任意非 SDL 事件多路复用。相反,您可以创建一个辅助线程,它使用select()epoll() 或围绕它们的一些包装器。该线程将等待网络消息,读取并解析它们,然后使用SDL_PushEvent 将请求传递给主线程。

【讨论】:

  • 不,我不想将事件推送到 SDL 队列,而是想找到一种以非阻塞方式轮询事件的方法 - 就像 SDL 对 SDL_PollEvent 所做的那样,是否有任何示例关于如何使用 poll 或 select 来实现的网络?如果可能没有多线程,基本上,如果没有等待读取的数据包,我想调用 recv 并立即返回
  • @Whiteclaws:您可以找到数千个关于如何在套接字上使用 select() 进行 IO 多路复用的示例,但是您将如何检查 SDL 事件?如果您确实需要检查 SDL 事件和套接字事件,您实际上可能需要进行主动轮询或忙等待:检查套接字中的数据,检查 SDL 队列中的事件,休眠一段时间,然后重复。此过程效率低下,但允许使用单个线程。
  • selectepoll 都不是完全非阻塞的;根据the manual for the former, "...select() 阻塞,直到指定的超时间隔,直到指定的条件对于至少一个指定的文件描述符为真",而后者是异步 I/O(与非阻塞 I/O 不同)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多