我正在使用libwebsockets
编写客户端,它是C的websocket库。
我想使用带有select()
的websocket文件描述符,这样我就可以在处理其他事件时处理websocket。
然后只有websocket得到一个事件,我才能调用libwebsocket_service();
来处理websocket事件。
所以我尝试了以下步骤。
通过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);
但它一直被阻止,但我认为必须唤醒,因为服务器在连接完成后发送消息。
--- ---- EDIT
经过更多测试。
似乎因为在连接完成之前调用了select()。 这意味着在处理LWS_CALLBACK_CLIENT_ESTABLISHED之前。
我在libwebsocket_service()
和libwebsocket_client_connect()
之间添加了select()
个,以便在调用LWS_CALLBACK_CLIENT_ESTABLISHED
之前处理select()
。
然后当它从服务器收到一些消息时,它与select()一起使用。
这意味着在处理LWS_CALLBACK_CLIENT_ESTABLISHED
后,套接字通常是打开的吗?
答案 0 :(得分:2)
你正试图把水推上山。
警告:我只编写了一个服务器,而不是客户端;但是,界面非常相似
首先,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在内部处理它的poll循环,但是在你正在与另一个集成的情况下 服务器,您需要让libwebsocket套接字与其他服务器共享一个轮询数组。这个 和其他与POLL_FD相关的回调允许您将专用的轮询数组接口代码放入 协议0的回调,你支持的第一个协议,通常是协议中的HTTP协议 服务案例。当需要将套接字添加到包含fd的轮询循环时,会发生此回调,而len是事件位图(如POLLIN)。如果您正在使用内部轮询循环(“服务”回调),则可以忽略这些回调。
LWS_CALLBACK_DEL_POLL_FD
当需要从外部轮询数组中删除套接字描述符时,会发生此回调。 in是套接字desricptor。如果您正在使用内部轮询循环,则可以忽略它。
LWS_CALLBACK_SET_MODE_POLL_FD
当libwebsockets想要修改套接字描述符的事件时,会发生此回调 处理程序应该对此套接字的pollfd结构的事件成员进行OR len 描述。如果您正在使用内部轮询循环,则可以忽略它。
LWS_CALLBACK_CLEAR_MODE_POLL_FD
当libwebsockets想要在其中修改套接字描述符的事件时,会发生此回调。 处理程序应该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上执行FD_SET
(和FD_CLEAR
)。你不是那样做的。这会引起问题。
答案 1 :(得分: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);
}
}
}
}
希望有所帮助