libwebsockets for C,我可以将websocket文件描述符与select()一起使用吗?



我正在使用客户端的libwebsockets编码,这是C的websocket库。

我想将 websocket 文件描述符与 select() 一起使用,以便我可以在处理其他事件的同时处理 websocket。

然后,只有当 WebSocket 有一个事件时,我才能调用 libwebsocket_service(); 来处理 WebSocket 事件。

所以我尝试了以下步骤。

  1. 通过struct libwebsocket *wsi = libwebsocket_client_connect(..)连接网络套接字我还检查了 reture 值是否为 NULL 错误。

  2. 通过 int fd = libwebsocket_get_socket_fd(wsi);获取文件描述符

  3. FD_SET(fd, &readFd);select(maxFd + 1, &readFd, NULL, NULL, NULL);

但是它一直被阻止,尽管我认为它必须被唤醒,因为服务器在连接完成后发送消息。

---编辑----

经过更多测试。

似乎是因为在连接完成之前调用了select()。这意味着在处理LWS_CALLBACK_CLIENT_ESTABLISHED之前。

我在libwebsocket_client_connect()select()之间再放libwebsocket_service()一个,以便它可以在调用select()之前处理LWS_CALLBACK_CLIENT_ESTABLISHED

然后当它从服务器接收到一些消息时,它与 select() 一起工作。

这意味着处理LWS_CALLBACK_CLIENT_ESTABLISHED后插座正常打开?

你正试图把水推上山。

警告:我只编写了一个执行此操作的服务器,而不是客户端;但是,界面非常相似。

首先,libwebsockets是在您将使用pollppoll而不是select的基础上编写的。我相信可以使用select,但是如果您使用pollppoll,您的生活会轻松得多;重写我的select()代码以使用ppoll大约需要 10 分钟。如果你真的想用select,我建议你用ppoll让外部轮询工作,然后重写使用select()

接下来,查看test-server.c,特别是如果定义了EXTERNAL_POLL代码,代码将如何更改。您还需要阅读 API 文档的以下内容:

接下来的四个原因是可选的,只有在您将集成时才需要注意 libwebsockets 套接字到外部轮询数组中。

LWS_CALLBACK_ADD_POLL_FD

libwebsocket 在内部处理其轮询循环,但在您与另一个集成的情况下 服务器 您需要让 libwebsocket 套接字与其他服务器共享轮询数组。这 其他POLL_FD相关的回调允许您将专用的轮询数组接口代码放入 协议 0 的回调,你支持的第一个协议,通常是 服务案例。当需要将套接字添加到包含 fd 的轮询循环中时,就会发生此回调,而 len 是事件位图(如 POLLIN)。如果您使用的是内部轮询循环("服务"回调),则可以忽略这些回调。

LWS_CALLBACK_DEL_POLL_FD

当需要从外部轮询数组中删除套接字描述符时,会发生此回调。 in 是套接字描述器。如果您使用的是内部轮询循环,则可以忽略它。

LWS_CALLBACK_SET_MODE_POLL_FD

当 libwebsockets 想要修改套接字描述符的事件时,会发生此回调 在。处理程序应 OR 借到此套接字的 pollfd 结构的事件成员 描述符。如果您使用的是内部轮询循环,则可以忽略它。

LWS_CALLBACK_CLEAR_MODE_POLL_FD

当 libwebsockets 想要修改 in 中的套接字描述符的事件时,会发生此回调。 处理程序应 AND ~len 到此套接字的 pollfd 结构的事件成员 描述符。如果您使用的是内部轮询循环,则可以忽略它。

这说明(简单地说)libwebsockets 会用这些方法调用你,并要求你操作你的poll数组。

忽略有关锁定的一些复杂性,您可以看到test-server.c这样实现它们:

    case LWS_CALLBACK_ADD_POLL_FD:
            if (count_pollfds >= max_poll_elements) {
                    lwsl_err("LWS_CALLBACK_ADD_POLL_FD: too many sockets to trackn");
                    return 1;
            }
            fd_lookup[pa->fd] = count_pollfds;
            pollfds[count_pollfds].fd = pa->fd;
            pollfds[count_pollfds].events = pa->events;
            pollfds[count_pollfds++].revents = 0;
            break;
    case LWS_CALLBACK_DEL_POLL_FD:
            if (!--count_pollfds)
                    break;
            m = fd_lookup[pa->fd];
            /* have the last guy take up the vacant slot */
            pollfds[m] = pollfds[count_pollfds];
            fd_lookup[pollfds[count_pollfds].fd] = m;
            break;

我不相信(服务器方)你需要实现后两个回调,test-server.c没有,我也没有。

调用 poll 后,您需要请求libwebsockets为其自己的 FD 提供服务,如下所示(再次来自 test-server.c):

            /*
             * this represents an existing server's single poll action
             * which also includes libwebsocket sockets
             */
            n = poll(pollfds, count_pollfds, 50);
            if (n < 0)
                    continue;

            if (n)
                    for (n = 0; n < count_pollfds; n++)
                            if (pollfds[n].revents)
                                    /*
                                    * returns immediately if the fd does not
                                    * match anything under libwebsockets
                                    * control
                                    */
                                    if (libwebsocket_service_fd(context,
                                                              &pollfds[n]) < 0)
                                            goto done;

那么,让我们回到您的具体问题:

所以我尝试了以下步骤。

  1. 通过struct libwebsocket *wsi = libwebsocket_client_connect(..)连接 websocket 我还检查了 reture 值是否为 NULL 错误。

  2. 通过int fd = libwebsocket_get_socket_fd(wsi);获取文件描述符

  3. FD_SET(fd, &readFd);select(maxFd + 1, &readFd, NULL, NULL, NULL);

但是它一直被阻止,尽管我认为它必须被唤醒,因为服务器在连接完成后发送消息。

好吧,除了 selectpoll 之间的阻抗不匹配之外,您在这里的问题似乎是

a) 您无条件地说要轮询 websocket 以供读取,并且

b) 你从来没有说你有数据要写入 Web 套接字。

当您

获得适当的回调时,您需要对读取和写入 FD 执行FD_SET(和FD_CLEAR)。你没有这样做。这将导致问题。

带选择(外部选择)

在 http.c 备份功能中

case LWS_CALLBACK_ADD_POLL_FD:
  FD_SET(pa->fd, &lista_zocalos);
      if (pa->fd > fd_max)
        fd_max = pa->fd;
  break;
case LWS_CALLBACK_DEL_POLL_FD:
  FD_CLR(pa->fd, &lista_zocalos);
  FD_CLR(pa->fd, &lista_zocalos_escritura);
  break;
case LWS_CALLBACK_CHANGE_MODE_POLL_FD:
  if (!pa->events) //a veces viene a 0                                                                                                       
    break;
  if(pa->events & POLLOUT)
    FD_SET(pa->fd, &lista_zocalos_escritura);
  else
    FD_CLR(pa->fd, &lista_zocalos_escritura);
  break;

在服务器中:

struct lws_pollfd pollfds;
fd_set lista_zocalos, readfds, lista_zocalos_escritura, writefds;
int fd_max;

while(){ //whatever in you while
  struct timeval tiempo;
  tiempo.tv_usec = 50000;  //1 segundo                                                                                                         
  tiempo.tv_sec = 0;
  readfds = lista_zocalos;
  writefds = lista_zocalos_escritura;
  status = select(fd_max + 1, &readfds, &writefds, (fd_set *)0, &tiempo);
  if (status >= 0){
   for (i = 0; i <= fd_max; i++){
     int manda_lws = 0;
     pollfds.revents = 0;
     if (FD_ISSET(i, &readfds)) {
       pollfds.revents = POLLIN;
       ioctl(i, FIONREAD, &caracteres);
       if (caracteres == 0)
         pollfds.revents |= POLLHUP;
       manda_lws++;
     }
     if (FD_ISSET(i, &writefds)) {
       pollfds.revents |= POLLOUT;
       manda_lws++;
     }
     if (manda_lws){
       pollfds.fd = i;
       pollfds.events = (FD_ISSET(i, &lista_zocalos) ? POLLIN : 0) | (FD_ISSET(i, &lista_zocalos_escritura) ? POLLOUT : 0);
       lws_service_fd(context, &pollfds);
     }
   }
 }

}

希望对你有帮助

相关内容

  • 没有找到相关文章

最新更新