1.说明
lighttpd
源码: https://github.com/lighttpd/lighttpd1.4.gitlighttpd wiki
: https://redmine.lighttpd.net/projects/lighttpd/wiki/libfcgi
: https://github.com/toshic/libfcgi/tree/master
注意:
2.编译
2.1 lighttpd
编译与web
访问
lighttpd
编译方法,可以参考文档:https://github.com/lighttpd/lighttpd1.4/blob/master/INSTALL,命令如下:
$ cd lighttpd-1.4.xx
$ ./autogen.sh
$ ./configure -C
$ make check
$ /usr/bin/sudo make install
安装后文件路径:
$ ls /usr/local/sbin/lighttpd* -al
-rwxr-xr-x 1 root root 2023608 8月 30 16:45 /usr/local/sbin/lighttpd
-rwxr-xr-x 1 root root 23080 8月 30 16:45 /usr/local/sbin/lighttpd-angel
配置文件lighttpd.conf
,使用:https://github.com/lighttpd/lighttpd1.4/blob/master/doc/config/lighttpd.conf。配置文件:modules.conf
,使用https://github.com/lighttpd/lighttpd1.4/blob/master/doc/config/modules.conf。/etc/lighttpd/conf.d/access_log.conf
使用https://github.com/lighttpd/lighttpd1.4/tree/master/doc/config/conf.d。
注释掉/etc/lighttpd/lighttpd.conf
:
#server.username = "lighttpd"
#server.groupname = "lighttpd"
修改/etc/lighttpd/lighttpd.conf
内容:
server.document-root = "/home/wityuan/Desktop/lighttpd/lighttpd1.4-lighttpd-1.4.76/www
server.port = 8080
server.bind = "localhost"
在目录:/home/wityuan/Desktop/lighttpd/lighttpd1.4-lighttpd-1.4.76/www
中添加test.html
,内容:
<!DOCTYPE html>
<html>
<head>
<title> first website </title></head><body>
<h1> welcome
</h1>
<p>this is a param.
</p>
</body>
</html>
执行命令:
$ sudo mkdir /var/log/lighttpd
$ sudo touch /var/log/lighttpd/error.log
启动lighttpd
:
# sudo /usr/local/sbin/lighttpd -f /etc/lighttpd/lighttpd.conf
启动成功:
网络访问:
http://127.0.0.1:8080/test.html
- 备注:
这一篇的文件配置可以参考文档: https://redmine.lighttpd.net/projects/lighttpd/wiki/InstallFromSource
2.2 libfcgi
下载与编译测试
从网站https://github.com/toshic/libfcgi/tree/master下载代码。
编译,使用命令:
$ ./configure
$ make
$ sudo make install
如果编译不过去,修改文件examples/Makefile.in
中的内容:
echo_cpp_LDADD = $(LIBDIR)/libfcgi++.la
改为:
echo_cpp_LDADD = $(LIBDIR)/libfcgi++.la $(LIBDIR)/libfcgi.la
最后,编译生成的目录信息如下:
编写程序文件cgitest1.c
:
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <alloca.h>
#include <fcgiapp.h>
#define LISTENSOCK_FILENO 0
#define LISTENSOCK_FLAGS 0
int main(int argc, char** argv) {
openlog("testfastcgi", LOG_CONS|LOG_NDELAY, LOG_USER);
int err = FCGX_Init(); /* call before Accept in multithreaded apps */
if (err) {
syslog (LOG_INFO, "FCGX_Init failed: %d", err); return 1; }
FCGX_Request cgi;
err = FCGX_InitRequest(&cgi, LISTENSOCK_FILENO, LISTENSOCK_FLAGS);
if (err) {
syslog(LOG_INFO, "FCGX_InitRequest failed: %d", err); return 2; }
while (1) {
err = FCGX_Accept_r(&cgi);
if (err) {
syslog(LOG_INFO, "FCGX_Accept_r stopped: %d", err); break; }
char** envp;
int size = 200;
for (envp = cgi.envp; *envp; ++envp) size += strlen(*envp) + 11;
char* result = (char*) alloca(size);
strcpy(result, "Status: 200 OK\r\nContent-Type: text/html\r\n\r\n");
strcat(result, "<html><head><title>testcgi</title></head><body><ul>\r\n");
for (envp = cgi.envp; *envp; ++envp) {
strcat(result, "<li>");
strcat(result, *envp);
strcat(result, "</li>\r\n");
}
strcat(result, "</ul></body></html>\r\n");
FCGX_PutStr(result, strlen(result), cgi.out);
}
return 0;
}
编译命令:
# gcc cgitest1.c -o cgitest1 -lfcgi
修改文件/etc/lighttpd/modules.conf
,增加内容:
...
server.modules += ("mod_fastcgi")
fastcgi.debug = 1
fastcgi.server += ("/cgi" =>
((
"bin-path" => "/home/wityuan/Desktop/lighttpd/cgicode/cgitest1",
"max-procs" => 1,
"socket" => "/tmp/fcgi_test.socket",
"check-local" => "disable",
"allow-x-send-file" => "enable"
)))
...
注意:
- 1.如果运行报错:
$ /usr/local/bin/cgi-fcgi
/usr/local/bin/cgi-fcgi: error while loading shared libraries: libfcgi.so.0: cannot open shared object file: No such file or directory
解决办法:
export LD_LIBRARY_PATH=/usr/local/lib
- 2.如果运行报错:
2024-08-30 23:59:14: (gw_backend.c.676) gw-backend failed to start: /xx/cgitest1
2024-08-30 23:59:14: (gw_backend.c.678) If you're trying to run your app as a FastCGI backend, make sure you're using the FastCGI-enabled version. If this is PHP on Gentoo, add 'fastcgi' to the USE flags. If this is PHP, try removing the bytecode caches for now and try again.
可以执行命令:
$ sudo ldconfig
重启lighttd
服务器,可以看到有2个进程:
访问资源,截图如下:
2.3 websocket
2.3.1 资源
websocket
的资源参考如下:
js
创建websocket
:https://websockets.spec.whatwg.org/#the-websocket-interfacewebsocket api
:https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_APIwebsocket-6455
官方文档:https://datatracker.ietf.org/doc/html/rfc6455
实际上,如上内容均在lighttpd
中可以看到:
2.3.2 websocket js
与后台程序通信
这里会用到网站所说的mod_wstunnel
的功能:
mod_wstunnel is a WebSocket tunnel endpoint, terminating the websocket tunnel from a client. mod_wstunnel decodes websocket frames and then passes data (without websocket frames) to a backend, and in the opposite direction encodes responses from backend into websocket frames before sending responses to client.
1.配置stunnel
在文件/etc/lighttpd/modules.conf
中新增mod_wstunnel
的配置:
..,
server.modules += ("mod_wstunnel")
$HTTP["url"] =~ "^/websocket" {
wstunnel.server = (
"" => ((
"host" => "127.0.0.1",
"port" => "8081"
))
)
wstunnel.frame-type = "text"
}
...
然后编写一个后台的server
程序,内容如下:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
// Should be same with the one in lihttpd.conf and index.html.
#define DEFAULT_PORT 8081
// Should be same with the one in lihttpd.conf.
#define DEFAULT_IP "127.0.0.1"
int main(int argc, char **argv)
{
int server_socket = -1;
int client_socket = -1;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
char received_buffer[1024]; // Buffer for received.
int received_len = -1;
int sended_len = -1;
int res = -1;
socklen_t addr_len = sizeof(struct sockaddr);
int index;
// Create a socket.
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket < 0)
{
printf("Create socket failed: %s\n", strerror(errno));
return -1;
}
// Bind the created socket on special IP and port.
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(DEFAULT_PORT);
server_addr.sin_addr.s_addr = inet_addr(DEFAULT_IP);
if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
{
printf("Bind server failed: %s\n", strerror(errno));
return -2;
}
printf("Socket[%d] has bond on port[%d] for IP address[%s]!\n",
server_socket, DEFAULT_PORT, DEFAULT_IP);
// Listen on the created socket.
listen(server_socket, 10);
while (1)
{
printf("Waiting and accept new client connect...\n");
client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &addr_len);
if (client_socket < 0)
{
printf("Accept client socket failed: %s\n", strerror(errno));
return -3;
}
printf("Accept new client[%d] socket[%s:%d]\n", client_socket,
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
while (1)
{
memset(received_buffer, 0, sizeof(received_buffer));
received_len = read(client_socket, received_buffer, sizeof(received_buffer));
if (received_len < 0)
{
printf("Read data from client [%d] failed: %s\n"