2

我正在libwebsockets为客户端编码,它是 C 的 websocket 库。

我想使用 websocket 文件描述符,select()这样我就可以在处理其他事件的同时处理 websocket。

然后只有当 websocket 收到事件时,我才能调用libwebsocket_service();来处理 websocket 事件。

所以我尝试了以下步骤。

  1. 通过连接 websocketstruct libwebsocket *wsi = libwebsocket_client_connect(..) 我还检查了返回值是否为 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 之前。

我在andlibwebsocket_service()之间多放了一个,这样它就可以在调用之前处理。libwebsocket_client_connect()select()LWS_CALLBACK_CLIENT_ESTABLISHEDselect()

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

这意味着处理后套接字是常开的LWS_CALLBACK_CLIENT_ESTABLISHED

4

2 回答 2

2

你正试图把水推上山。

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

首先,libwebsockets是根据您将使用pollorppoll而不是select. 我确信它是可以使用的,但是如果你使用or select,你的生活会轻松很多;重写我的代码使用大约需要 10 分钟。如果你真的要使用,我建议你让外部轮询工作使用,然后重写使用。pollppollselect()ppollselectppollselect()

接下来,看一下,特别是如果定义test-server.c了代码是如何变化的。EXTERNAL_POLL您还想阅读以下 API 文档:

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

LWS_CALLBACK_ADD_POLL_FD

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

LWS_CALLBACK_DEL_POLL_FD

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

LWS_CALLBACK_SET_MODE_POLL_FD

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

LWS_CALLBACK_CLEAR_MODE_POLL_FD

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

这就是说(简单地说)是 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 track\n");
                    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. 通过连接 websocketstruct libwebsocket *wsi = libwebsocket_client_connect(..)我还检查了返回值是否为 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)您永远不会说您有数据要写入网络套接字。

当您获得适当的回调时,您需要对读取和写入 FD 执行FD_SETFD_CLEAR操作。你没有那样做。这会导致问题。

于 2014-11-28T18:04:39.700 回答
0

带选择(外部选择)

在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;

在 server.c 中:

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);
     }
   }
 }

}

希望能帮助到你

于 2018-05-03T17:12:22.677 回答