关于使用lws编程的注意事项
后台进程
有一个默认构建的助手api lws_daemonize
,它可以很好地完成守护所需的一切,包括创建锁文件。如果你正在做一个基本上是守护进程的东西,只需在初始化的早期调用它就可以fork到一个无头(headless)后台进程并退出启动进程。
请注意,stdout、stderr和stdin都被重定向到/dev/null,以强制您的守护程序是无头(headless)的,因此您需要通过syslog来整理其他日志记录。
最大连接数
库可以处理的最大连接数是在开始时通过查询操作系统来确定允许打开多少个文件描述符(例如,在Fedora上为1024个)来决定的。然后,它分配最多允许这么多连接的数组,减去用户代码使用的任何其他文件描述符。
如果要限制或增加分配,可以使用ulimit或类似方法更改可用的文件描述符数量,重新启动时libwebsockets将相应地进行调整。
Libwebsockets是单线程的
Libwebsockets在单个线程中的序列化事件循环中工作。
不允许从其他线程直接执行websocket操作。除了 forked()
进程中的内部数据不一致之外,wsi
(struct websocket
)的作用域可以在服务期间的任何时间结束,同时关闭套接字并释放 wsi
。
Websocket写入活动应仅在 LWS_CALLBACK_SERVER_WRITEABLE
回调中进行,如下所述。
网络编程需要将新数据的发布与获取先前数据的对等方联系起来,这对所有用户来说并不明显,所以让我们重复一下,换言之:
仅从可写回调执行LWS_WRITE
还有一个网络编程真理让一些人惊讶,那就是如果数据接收器不能接受更多:
必须执行RX流控制
有关示例代码,请参见镜像协议实现。
用户回调中只显示活动连接,因此这消除了尝试使用关闭和释放的wsis的任何可能性。
如果您需要为其他套接字或文件描述符以及websocket描述符提供服务,您可以将它们与websocket描述符组合在一个轮询循环中,请参见下面的“外部轮询循环支持”,并仍然在一个线程/进程上下文中完成所有操作。
如果您坚持尝试从多个线程使用它,请特别注意您是否可能同时从不同的线程创建多个上下文。
SSL_library_init() 是从上下文创建api调用的,它也是不可重入的。因此,至少要按顺序创建上下文。
仅在套接字可写时发送数据
您应该只通过在websocket连接上的用户回调LWS_CALLBACK_SERVER_WRITEABLE
(或者对客户来说是LWS_CALLBACK_CLIENT_WRITEABLE
)中发送数据。
如果您想发送某个东西,不要只发送它,而是在套接字可写时请求一个回调
lws_callback_on_writable(context, wsi)
对于特定的wsi
, 或者lws_callback_on_writable_all_protocol(protocol)
所有使用该协议的连接在下一次可写时获得回调。
通常,在下一次服务循环中您会立即被回调,但如果您的对等设备速度慢或暂时不活动,则回调会相应延迟。生成要写入的内容并发送它应该在…WRITEABLE回调中完成。
有关如何执行此操作的示例,请参见测试服务器代码
不要只依赖您自己出现的可写请求
如果Libwebsockets满足必须在内部缓冲发送数据的网络条件,它可能会生成额外的LWS_CALLBACK_CLIENT_WRITEABLE
事件。
因此,您的 LWS_CALLBACK_CLIENT_WRITEABLE
代码需要自己决定发送什么,它不能认为仅仅因为可写回调来了,就真的该发送什么了。
你很有可能在任何时候得到一个“额外的”可写回调,只需要return 0
,然后等待预期的回调。
从用户端关闭连接
当您想关闭一个连接时,可以通过从该连接的回调中返回“-1”来完成。
您可以通过在wsi上调用 lws_callback_on_writable
来触发回调,然后在回调中想要关闭它时返回-1。但通常,关闭的决定已经在回调中做出,返回-1很简单。
如果套接字知道连接已断开,因为对等端已关闭或出现了肯定的网络错误(如FIN),那么libwebsocket将自动关闭连接。
如果您有一个无声的死连接,则有可能进入一种状态,即连接上的发送管道被阻塞,但不会出现确认,因此死连接永远不会变为可写。为此,您可以使用TCP keepalive(请参阅本文后面的内容)或ping。
从zip文件中提供
Lws现在支持从zip容器中提供gzipped文件。感谢Per Bothner贡献代码。
这样做的好处是,如果客户端可以接受GZIP编码,lws可以简单地从zip文件中发送GZIP压缩文件,而无需进一步处理,从而节省时间和带宽。
如果客户端无法理解gzip压缩,lws会自动解压缩文件并正常发送。
存储和RAM有限的客户会发现这很有用;在受限制的存储器中,每次只有一个输入缓冲器在存储器中。
要使用此功能,请确保在CMake上启用了LWS_WITH_ZIP_FOPS
(默认情况下是启用的)。
libwebsockets-test-server-v2.0
已经包含了一个使用该技术的挂载,运行该测试服务器并导航到http://localhost:7681/ziptest/candide.html
这将提供html的Candide一书,以及两个jpg,所有这些都来自一个zip文件中:/usr/[local/]share-libwebsockets-test-server/candide.zip
否则,使用是自动的,如果您安排一个指向zip文件的挂载,例如“/ziptest”->“mypath/test.zip”,则URL为 /ziptest/index.html
将从index.html
映射到内部的 mypath/test.zip
零碎的消息
要支持碎片化消息,您需要使用lws_is_final_fragment
检查消息的最后一帧。此检查可以与libwebsockets_remaining_packet_payload
结合使用,以收集消息的全部内容,例如:
case LWS_CALLBACK_RECEIVE:
{
Client * const client = (Client *)user;
const size_t remaining = lws_remaining_packet_payload(wsi);
if (!remaining && lws_is_final_fragment(wsi)) {
if (client->HasFragments()) {
client->AppendMessageFragment(in, len, 0);
in = (void *)client->GetMessage();
len = client->GetMessageLength();
}
client->ProcessMessage((char *)in, len, wsi);
client->ResetMessage();
} else
client->AppendMessageFragment(in, len, remaining);
}
break;
测试示例libwebsockets-test-fraggle也展示了如何处理碎片消息。
调试日志记录
同样使用lws_set_log_level
api,您可以提供自定义回调来实际发出日志字符串。默认情况下,这指向发送到stderr的内部emit函数。设置为 NULL
将使其保持原样。
从库中导出助手函数 lwsl_emit_syslog()
,以简化对syslog的日志记录。您仍然需要在用户代码中使用setlogmask
, openlog
和closelog
。
日志api可用于用户代码。
lwsl_err(...)
lwsl_warn(...)
lwsl_notice(...)
lwsl_info(...)
lwsl_debug(...)
通知和信息的区别在于,默认情况下,通知将被记录,而默认情况下信息将被忽略。
如果您没有使用_DEBUG定义进行构建,即没有
$ cmake .. -DCMAKE_BUILD_TYPE=DEBUG
那么低于通知的日志级别实际上不会被编译。
外部轮询循环支持
libwebsockets为其所有套接字维护一个内部的 poll()
数组,但您可以将套接字集成到一个外部轮询数组中。如果libwebsockets将与另一台服务器维护的现有轮询阵列协作,则需要这样做。
四个回调LWS_CALLBACK_ADD_POLL_FD
, LWS_CALLBACK_DEL_POLL_FD
,LWS_CALLBACK_SET_MODE_POLL_FD
和LWS_CALLBACK_CLEAR_MODE_POLL_FD
出现在协议0的回调中,并允许接口代码管理其他轮询循环中的套接字描述符。
您可以将所有需要服务的pollfd传递给lws_service_fd()
,即使套接字或文件不属于libwebsockets也是安全的。
如果libwebsocket处理了它,它会在返回之前将pollfd revents
字段置零。因此,您可以让libwebsockets尝试,如果返回时 pollfd->revents
为非零,您知道它需要由您的代码处理。
还要注意,当集成像libev或libuv这样的外部事件循环时,如果它本身不使用 poll() 语义,则必须返回反映真实事件的假pollfd:
- 确保在合成的pollfd中将.events设置为.revents值
- 如果可能,请检查事件循环的内置支持(例如./lib/libuv.c),以了解它如何与lws相关联
- 使用 libwebsockets.h中的 LWS_POLLHUP / LWS_POLLIN / LWS_POLLOUT 以避免失去windows兼容性
在c++应用程序中使用
该库已准备好供C++应用程序使用。您可以通过复制测试服务器快速入门
$ cp test-server/test-server.c test.cpp
并像这样用C++构建
$ g++ -DINSTALL_DATADIR=\"/usr/share\" -ocpptest test.cpp -lwebsockets
INSTALL_DATADIR
是需要的,因为测试服务器使用了它,如果您在应用程序中删除了对它的引用,则不需要在g++行上定义它。
http请求头信息的可用性
HTTP头信息由“ah”结构体构成的池所管理。这些是有限的资源,因此需要释放http头并将ah返回池以供重用。
因此,在ESTABLISHED回调后,升级到websockets的HTTP连接的标头信息将丢失。之前用户代码没有处理的任何重要内容都应该拷贝出来,以便以后使用。
对于不升级的HTTP连接,标头信息始终可用。
TCP Keepalive
不用于发送的连接可能会在对等方和不发送的一方之间的某个位置无声地死亡。在这种情况下,默认情况下,TCP不会报告任何内容,并且在您尝试发送之前,您将永远不会收到更多的传入数据或表明链接已断开。
为了处理这种情况的通知,您可以选择在创建上下文时启用所有libwebsockets套接字上的TCP保持活动(keepalive)。
要启用keepalive,请在上下文创建时将上下文创建参数结构体的ka_time成员设置为非零值(以秒为单位)。在这种情况下,您还应该填写ka_probe和ka_interval。
在启用keepalive的情况下,TCP层将发送控制数据包,这些数据包应在不影响链路流量的情况下激发对等方的响应。如果没有响应,套接字将在 poll()
处宣布错误,强制关闭。
请注意,BSD不像Linux那样支持每个套接字的保活时间/探针/间隔。在这些系统上,您可以通过ka_time
中的非零值启用keepalive,但无论ka_time
中有什么非零值,都会使用时间/探针/间隔的全系统内核设置。
优化SSL连接
lws_context_creation_info
结构体中有一个成员ssl_cipher_list
,它允许用户代码在上下文创建时限制可能的密码选择。
您可能希望对此进行研究,以阻止ssl对等体选择计算成本太高的密码。要使用它,请将其指向一个字符串,如
"RC4-MD5:RC4-SHA:AES128-SHA:AES256-SHA:HIGH:!DSS:!aNULL"
如果保留 NULL
,则可以选择“DEFAULT”密码集。
您还可以将其设置为 "ALL"
,以允许一切(包括不安全的密码)。
客户端连接的异步特性
当您调用 lws_client_connect_info(..)
并返回 wsi
时,并不意味着您的连接处于活动状态。这只是意味着它开始尝试连接。
只有在收到 LWS_CALLBACK_CLIENT_ESTABLISHED
时,客户端连接才处于活动状态。
连接有5秒的超时,它可能会因为其他原因而放弃或死亡,如果发生任何情况,您将在协议0上得到 LWS_CALLBACK_CLIENT_CONNECTION_ERROR
回调,而不是wsi
。
在尝试连接并返回非空wsi
后,您应该循环调用 lws_service()
,直到出现上述回调之一。
通常,请参见test-client.c 以获取示例代码。
请注意,客户端连接api在返回之前会尝试进行一些连接。这意味着,在您的用户代码有机会返回wsi以识别它之前,可以在新连接上获得类似CONNECTION_ERROR的回调(事实上,如果连接确实提前失败,则将返回NULL而不是wsi)。
为了避免这个问题,您可以在客户端连接信息结构中填写 pwsi
,以指向一个结构体lws,该结构体由客户端连接api使用相关wsi提前填写。然后,您可以在回调中进行检查,以确认失败客户端连接的身份。
Lws平台独立的文件访问api
lws现在以一种方式公开了他的内部平台文件抽象,既可以由用户代码使用,使其不受平台限制,也可以被用户代码覆盖或子类化。这允许将URI“目录空间”作为一个虚拟文件系统来处理,该虚拟文件系统可以由常规文件系统支持,也可以不由普通文件系统支持。一个示例用法是从大型压缩归档存储中提供文件,而不必解压缩除请求的文件之外的任何内容。
测试服务器展示了如何使用它,基本上,lws的平台特定部分准备了一个存在于lws上下文中的文件操作结构。
用户代码可以获取指向文件操作结构的指针
LWS_VISIBLE LWS_EXTERN struct lws_plat_file_ops *
`lws_get_fops`(struct lws_context *context);
然后还可以使用助手来利用这些独立于平台的文件处理api
lws_fop_fd_t
`lws_plat_file_open`(struct lws_plat_file_ops *fops, const char *filename,
lws_fop_flags_t *flags)
int
`lws_plat_file_close`(lws_fop_fd_t fop_fd)
unsigned long
`lws_plat_file_seek_cur`(lws_fop_fd_t fop_fd, lws_fileofs_t offset)
int
`lws_plat_file_read`(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
uint8_t *buf, lws_filepos_t len)
int
`lws_plat_file_write`(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
uint8_t *buf, lws_filepos_t len )
提供了通用助手,可访问通用fop信息或调用上面的fops函数
lws_filepos_t
lws_vfs_tell(lws_fop_fd_t fop_fd);
lws_filepos_t
lws_vfs_get_length(lws_fop_fd_t fop_fd);
uint32_t
lws_vfs_get_mod_time(lws_fop_fd_t fop_fd);
lws_fileofs_t
lws_vfs_file_seek_set(lws_fop_fd_t fop_fd, lws_fileofs_t offset);
lws_fileofs_t
lws_vfs_file_seek_end(lws_fop_fd_t fop_fd, lws_fileofs_t offset);
用户代码还可以覆盖或子类化文件操作,以包装或替换它们。测试服务器中显示了一个示例。
从v2.1到fops之前的更改
有以下几个变化:
-
2.2版之前的fops直接使用平台文件描述符。当前fops返回并接受一个包装器类型lws_fop_fd_t,它是一个指向malloc’d结构体的指针,该结构包含特定于文件系统实现的信息。
-
2.2前fops将fops绑定到wsi。这是完全删除的,您只需在打开该文件时提供一个指向应用于该文件的fops结构体的指针。之后,fops中的操作只需要返回打开的lws_fop_fd_t。
-
所有内容都用typedefs包装。有关如何实现的示例,请参见lws-plat-unix.c。
-
文件中的位置、文件长度和打开后留下的Flags副本现在一般保存在fop_fd中。
VFS实现现在必须设置和管理此通用信息。请参见示例中lws-plat-unix.c的实现。 -
文件长度不再设置为open() fop提供的指针。提供api
lws_vfs_get_length()
以获取打开后的文件长度。 -
如果您的文件命名空间是虚拟的,即平台fop无法直接访问,则必须在打开期间在标志上设置LWS_FOP_FLAG_VIRTUAL。
-
通用fop_fd中有一个可选的
mod_time
uint32_t成员。如果您能够在打开期间进行设置,则应通过在标志上设置LWS_FOP_FLAG_MOD_TIME_VALID
。
RAW文件描述符轮询
LWS允许您在LWS服务/轮询/事件循环中包含通用平台文件描述符。
正常打开fd,然后
lws_sock_file_fd_type u;
u.filefd = your_open_file_fd;
if (!lws_adopt_descriptor_vhost(vhost, 0, u,
"protocol-name-to-bind-to",
optional_wsi_parent_or_NULL)) {
// failed
}
// OK
为文件fd创建了一个wsi,它与其他wsi类似,您将在指定的协议上得到这些回调
LWS_CALLBACK_RAW_ADOPT_FILE
LWS_CALLBACK_RAW_RX_FILE
LWS_CALLBACK_RAW_WRITEABLE_FILE
LWS_CALLBACK_RAW_CLOSE_FILE
以 LWS_CALLBACK_RAW_ADOPT_FILE开始。
protocol-lws-raw-test
插件提供了一种使用libwebsockets-test-server-v2.0
进行测试的方法:
该插件在您的系统上创建一个名为 “/tmp/lws-test-raw” 的FIFO。
你可以像这样通过FIFO输入数据:
$ sudo sh -c "echo hello > /tmp/lws-test-raw"
这个插件只是简单地打印数据。但它是通过lws事件循环/服务轮询来实现的。
RAW服务器套接字描述符轮询
除了HTTP[s]和WS[s]之外,您还可以使vhost接受RAW套接字连接。如果写入连接的第一个字节不是有效的HTTP方法,则连接切换到RAW模式。
这在默认情况下是禁用的,您可以在创建vhost时通过设置.options
的LWS_SERVER_OPTION_FALLBACK_TO_RAW 标志位来启用它。
RAW模式套接字连接接收以下回调
LWS_CALLBACK_RAW_ADOPT
LWS_CALLBACK_RAW_RX
LWS_CALLBACK_RAW_WRITEABLE
LWS_CALLBACK_RAW_CLOSE
您可以通过用pvo raw
来标记所选的协议以控制vhost上的哪个协议处理这些RAW模式的传入连接,例如
"protocol-lws-raw-test": {
"status": "ok",
"raw": "1"
},
“raw”pvo将此协议标记为用于raw连接。
protocol-lws-raw-test
插件提供了一种使用 libwebsockets-test-server-v2.0
进行测试的方法:
运行 libwebsockets-test-server-v2.0 并通过 telnet 连接到它,例如
$ telnet 127.0.0.1 7681
在连接超时之前,键入不是有效的HTTP方法并输入。连接将使用此协议切换到RAW模式,并将未使用的rx作为原始rx回调传递。
测试协议将在telnet上键入的内容回传给telnet。
RAW客户端套接字描述符轮询
现在,您还可以在客户端模式下打开RAW套接字连接。
按照通常的方法创建客户端连接,但将info.method
设置为“RAW”。建立连接后,wsi将转换为RAW模式,并使用与上述服务器RAW套接字相同的回调进行操作。
libwebsockets-test-client使用 raw://URLS 支持这一点。要进行测试,请在一个窗口中打开一个netcat侦听器
$ nc -l 9999
在另一个窗口中,使用测试客户端连接到它
$ libwebsockets-test-client raw://127.0.0.1:9999
连接应该成功,客户端将接收在netcat窗口中键入的文本(包括CRLF)。
ECDH支持
现在支持ECDH证书。按如下启用CMake选项
cmake .. -DLWS_SSL_SERVER_WITH_ECDH_CERT=1
和 info->options标志位
LWS_SERVER_OPTION_SSL_ECDH
以构建支持并在运行时选择它。
SMP/多线程服务
SMP已经集成到LWS中,无需任何内部线程。使用起来非常简单,libwebsockets-test-server-pthread 展示了如何做到这一点,在那里使用 -j<n> 参数将服务线程的数量控制在32个以内。
信息结构中添加了两个新成员
unsigned int count_threads;
unsigned int fd_limit_per_thread;
将它们保留为默认值0,以获得正常的单线程服务循环。
将count_threads设置为n,告诉lws您将有n个同时在上下文上运行的服务线程。
无论有多少服务线程,一个端口上仍然只有一个侦听套接字。
当建立连接时,服务线程会接受该连接,同时最少的连接处于活动状态,以执行负载平衡。
用户代码负责生成运行与特定tsi(线程服务索引,0…n-1)相关联的服务循环的n个线程。请参阅 libwebsockets-test-server-pthread 了解如何操作。
如果将fd_limit_per_thread设置为0,则服务线程之间共享fds的进程限制;如果您的进程被允许总共1024 fds,那么每个线程被限制为1024/n。
您可以将fd_limit_per_thread设置为一个非零数字来手动控制,例如,支持的fd总限制小于进程允许值。
您可以在Cmake时使用-DLWS_MAX_SMP=控制多线程的上下文基本数据分配,如果未给定,则将其设置为32。线程的serv_buf分配(当前为4096)仅在运行时针对活动线程进行。
由于lws将根据 LWS_MAX_SMP 限制请求的实际支持线程数,因此可以从api lws_get_count_threads(上下文)来查询创建上下文时实际允许的线程数。
对于FD锁定回调,需要以 libwebsockets-test-server-pthread 的方式在用户代码中实现锁定。
lws本身对pthreads没有任何了解或依赖。如何实现锁定完全取决于用户代码。
Libev/Libuv支持
您可以选择其中之一或两者
-DLWS_WITH_LIBEV=1
-DLWS_WITH_LIBUV=1
在cmake配置时。用户应用程序可以使用其中一个上下文初始化选项标志
LWS_SERVER_OPTION_LIBEV
LWS_SERVER_OPTION_LIBUV
以指示它将使用任一事件库。
来自用户代码的扩展选项控件
用户代码现在可以使用新的api lws_set_extension_option()
设置每个连接扩展选项。
这应该像这样从ESTABLISHED回调中调用
lws_set_extension_option(wsi, "permessage-deflate",
"rx_buf_size", "12"); /* 1 << 12 */
如果扩展未激活(丢失或未协商连接,或库中禁用了扩展),则调用仅返回-1。否则,连接的扩展已更改其命名选项。
扩展可以决定更改或不允许更改,在上面的示例中,permessage-deflate 限制其rx输出缓冲区的大小,同时考虑到协议的rx_buf_size成员。
客户端连接为HTTP[S]而不是WS[S]
您可以使用用于创建客户端 ws[s] 连接的相同结构体 lws_client_connect_info 打开通用 http 客户端连接。
要保持在 http[s] 中,请将可选的信息成员“method”设置为指向字符串“GET”,而不是默认的NULL。
处理完服务器标头后,当服务器的有效负载可用时,将调用回调LWS_CALLBACK_RECEIVE_CLIENT_HTTP。
您可以选择是立即处理数据,还是在传出套接字可写时对回调进行排队以提供流控制,并在可写回调中处理数据。
无论哪种方式,都可以使用 lws_http_client_read()
访问数据,例如
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
{
char buffer[1024 + LWS_PRE];
char *px = buffer + LWS_PRE;
int lenx = sizeof(buffer) - LWS_PRE;
lwsl_notice("LWS_CALLBACK_RECEIVE_CLIENT_HTTP\n");
/*
* Often you need to flow control this by something
* else being writable. In that case call the api
* to get a callback when writable here, and do the
* pending client read in the writeable callback of
* the output.
*/
if (lws_http_client_read(wsi, &px, &lenx) < 0)
return -1;
while (lenx--)
putchar(*px++);
}
break;
请注意,如果您将在vhost上使用SSL客户端连接,则必须在创建vhost之后为vhost准备客户端SSL上下文,因为如果vhost设置为侦听/服务,通常不会这样做。调用 api lws_init_vhost_client_ssl() 也允许vhost上的客户端ssl。
使用lws vhosts
如果在创建上下文时设置 LWS_SERVER_OPTION_EXPLICIT_VHOSTS 选项标志,则不会使用信息结构成员创建默认vhost,以实现兼容性。相反,您可以在之后调用 lws_create_vhost() 手动附加一个或多个vhost。
LWS_VISIBLE struct lws_vhost *
lws_create_vhost(struct lws_context *context,
struct lws_context_creation_info *info);
lws_create_vhost() 使用与 lws_create_context() 相同的结构体,它忽略与上下文相关的成员,并使用对vhost有意义的成员(在libwebsockets.h中用VH标记)。
struct lws_context_creation_info {
int port; /* VH */
const char *iface; /* VH */
const struct lws_protocols *protocols; /* VH */
const struct lws_extension *extensions; /* VH */
...
当您连接vhost时,如果vhost的端口已经有一个侦听套接字,那么两个vhost都会共享它,并使用SNI(正在使用SSL)或客户端的 Host: header 来选择正确的一个。或者如果没有其他vhost已经在侦听,则创建一个新的侦听套接字。
有一些新成员,但主要是在上下文创建时设置的内容。
lws如何将主机名或SNI与vhost匹配
首先剥离任何尾随的:端口号。
然后,它尝试找到一个在正确端口上侦听的vhost的确切名称匹配,即如果SNI或Host:header提供了abc.com:1234,它将匹配在端口1234上侦听,名字为abc.com的vhost。
如果没有完全匹配,lws将考虑通配符匹配,例如,客户端通过SNI或Host:header提供 cats.abc.com:1234,它将接受在端口1234上侦听,名字为“abc.com”的vhost。如果有更好、准确的匹配,则会优先选择它。
使用SSL的连接仍然会让客户端继续检查证书是否允许通配符,如果不允许,则会出错。
在vhost上使用lws挂载
lws_create_vhost() 的最后一个参数允许您将 lws_http_mount 结构的链接列表与该vhost的URL“名称空间”相关联,这与unix允许您将文件系统装载到/文件系统的区域中的方式类似,并可以透明地处理内容。
struct lws_http_mount {
struct lws_http_mount *mount_next;
const char *mountpoint; /* mountpoint in http pathspace, eg, "/" */
const char *origin; /* path to be mounted, eg, "/var/www/warmcat.com" */
const char *def; /* default target, eg, "index.html" */
struct lws_protocol_vhost_options *cgienv;
int cgi_timeout;
int cache_max_age;
unsigned int cache_reusable:1;
unsigned int cache_revalidate:1;
unsigned int cache_intermediaries:1;
unsigned char origin_protocol;
unsigned char mountpoint_len;
};
最后一个装载结构应具有NULL mount_next,否则它应指向列表中的“下一个”装载结构。
装载结构和字符串都必须持久存在,直到上下文被破坏,因为它们不会被复制,而是被就地使用。
.origin_protocol
应该是以下其中一个:
enum {
LWSMPRO_HTTP,
LWSMPRO_HTTPS,
LWSMPRO_FILE,
LWSMPRO_CGI,
LWSMPRO_REDIR_HTTP,
LWSMPRO_REDIR_HTTPS,
LWSMPRO_CALLBACK,
};
-
LWSMPRO_FILE 用于将url命名空间映射到文件系统目录并自动为其提供服务。
-
LWSMPRO_CGI 将url名称空间与给定的CGI可执行文件相关联,当访问url并将输出提供给客户端时,CGI可执行程序将运行。
-
LWSMPRO_REDIR_HTTP 和 LWSMPRO_REDIR_HTTPS 自动将客户端重定向到给定的源URL。
-
LWSMPRO_CALLBACK 导致http连接附加到与命名协议(可能是插件)相关联的回调。
LWSMPRO_CALLBACK挂载操作
CALLBACK类型挂载提供的功能是将URL命名空间的一部分绑定到命名的协议回调处理程序。
这允许协议插件处理URL命名空间的区域。例如,在 test-server-v2.0.c 中,URL区域 “/formtest” 与提供 “protocol-post-demo” 的插件相关联,如下所示
static const struct lws_http_mount mount_post = {
NULL, /* linked-list pointer to next*/
"/formtest", /* mountpoint in URL namespace on this vhost */
"protocol-post-demo", /* handler */
NULL, /* default filename if none given */
NULL,
0,
0,
0,
0,
0,
LWSMPRO_CALLBACK, /* origin points to a callback */
9, /* strlen("/formtest"), ie length of the mountpoint */
};
客户机对 /formtest[anything] 的访问将传递给使用命名协议注册的回调,在本例中由协议插件提供。
所有方法(如GET和POST)的访问都由回调处理。
protocol-post-demo 处理接受和响应测试服务器html中的html表单。
当连接访问与CALLBACK类型装载相关的URL时,将更改连接协议,直到下次访问同一CALLBACK装载区域之外的URL。连接上的用户空间被安排为协议结构中给定的新协议用户空间分配的大小。
只有当连接使用不同的协议访问URL区域时,才会删除/替换此分配(如果没有CALLBACK区域与其匹配,则使用默认协议[0])。
连接丢失时网页变暗
lws测试插件的html在网页上提供了关于它是否仍然连接到服务器的有用反馈,如果没有,则变暗页面。您也可以轻松地将其添加到自己的html中。
-
在网页头位置包含 lws-common.js 文件
<script src=“/lws-common.js”></script> -
在脚本中设置页面在初始化时变暗。
lws_gray_out(true,{‘zindex’:‘499’}); -
在 ws onOpen()中, 移除变暗。
lws_gray_out(false); -
在 ws onClose(), 让页面变暗
lws_gray_out(true,{‘zindex’:‘499’});