你想把水推上山。
警告:我只写了一个服务器,而不是客户端;但是,界面非常相似
首先,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 想要修改套接字描述符的事件时,会发生此回调
in. 处理程序应该或 len 到该套接字的 pollfd 结构的 events 成员
描述符。如果您使用的是内部轮询循环,则可以忽略它。
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;
那么,让我们回到您的具体问题:
所以我尝试了以下步骤。
通过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) 你从来没有说你有数据要写入网络套接字。
当您获得适当的回调时,您需要在两者上执行FD_SET(和FD_CLEAR)读取和写入FD。你没有那样做。这会导致问题。