我正在使用客户端的libwebsockets
编码,这是C的websocket库。
我想将 websocket 文件描述符与 select()
一起使用,以便我可以在处理其他事件的同时处理 websocket。
然后,只有当 WebSocket 有一个事件时,我才能调用 libwebsocket_service();
来处理 WebSocket 事件。
所以我尝试了以下步骤。
-
通过
struct libwebsocket *wsi = libwebsocket_client_connect(..)
连接网络套接字我还检查了 reture 值是否为 NULL 错误。 -
通过 int
fd = libwebsocket_get_socket_fd(wsi);
获取文件描述符 -
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
是在您将使用poll
或ppoll
而不是select
的基础上编写的。我相信可以使用select
,但是如果您使用poll
或ppoll
,您的生活会轻松得多;重写我的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;
那么,让我们回到您的具体问题:
所以我尝试了以下步骤。
通过
struct libwebsocket *wsi = libwebsocket_client_connect(..)
连接 websocket 我还检查了 reture 值是否为 NULL 错误。通过
int fd = libwebsocket_get_socket_fd(wsi);
获取文件描述符
FD_SET(fd, &readFd);
和select(maxFd + 1, &readFd, NULL, NULL, NULL);
但是它一直被阻止,尽管我认为它必须被唤醒,因为服务器在连接完成后发送消息。
好吧,除了 select
和 poll
之间的阻抗不匹配之外,您在这里的问题似乎是
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);
}
}
}
}
希望对你有帮助