BMC lighttpd kvm数据分析(websocket)

1.说明

  1. lighttpd源码: https://github.com/lighttpd/lighttpd1.4.git
  2. lighttpd wiki: https://redmine.lighttpd.net/projects/lighttpd/wiki/
  3. libfcgi: https://github.com/toshic/libfcgi/tree/master

注意:

2.编译

2.1 lighttpd编译与web访问

lighttpd编译方法,可以参考文档:https://github.com/lighttpd/lighttpd1.4/blob/master/INSTALL,命令如下:

c 复制代码
  $ cd lighttpd-1.4.xx
  $ ./autogen.sh
  $ ./configure -C
  $ make check
  $ /usr/bin/sudo make install

安装后文件路径:

c 复制代码
$ 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:

c 复制代码
#server.username  = "lighttpd"
#server.groupname = "lighttpd"

修改/etc/lighttpd/lighttpd.conf内容:

c 复制代码
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,内容:

c 复制代码
<!DOCTYPE html>
<html>
        <head>    
                <title> first website </title></head><body>    
                <h1> welcome
                </h1>   
                <p>this is a param.
                </p>
        </body>
</html>

执行命令:

c 复制代码
$ sudo mkdir /var/log/lighttpd
$ sudo touch /var/log/lighttpd/error.log

启动lighttpd:

c 复制代码
# sudo /usr/local/sbin/lighttpd -f /etc/lighttpd/lighttpd.conf

启动成功:

网络访问:

c 复制代码
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下载代码。

编译,使用命令:

c 复制代码
$ ./configure
$ make
$ sudo make install

如果编译不过去,修改文件examples/Makefile.in中的内容:

c 复制代码
echo_cpp_LDADD = $(LIBDIR)/libfcgi++.la

改为:

c 复制代码
echo_cpp_LDADD = $(LIBDIR)/libfcgi++.la $(LIBDIR)/libfcgi.la

最后,编译生成的目录信息如下:

编写程序文件cgitest1.c

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;
}

编译命令:

c 复制代码
# gcc cgitest1.c -o cgitest1 -lfcgi

修改文件/etc/lighttpd/modules.conf,增加内容:

c 复制代码
...
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.如果运行报错:
c 复制代码
$ /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

可以参考:https://serverfault.com/questions/120233/how-to-configure-fastcgi-to-work-with-ligttpd-in-ubuntu

解决办法:

c 复制代码
 export LD_LIBRARY_PATH=/usr/local/lib
  • 2.如果运行报错:
c 复制代码
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.

可以执行命令:

c 复制代码
$ sudo ldconfig

重启lighttd服务器,可以看到有2个进程:

访问资源,截图如下:

2.3 websocket

2.3.1 资源

websocket的资源参考如下:

实际上,如上内容均在lighttpd中可以看到:

2.3.2 websocket js与后台程序通信

这里会用到网站所说的mod_wstunnel的功能:

c 复制代码
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的配置:

c 复制代码
..,
server.modules += ("mod_wstunnel")
$HTTP["url"] =~ "^/websocket" {
  wstunnel.server = (
    "" => ((
      "host" => "127.0.0.1",
      "port" => "8081"
    ))
  )
  wstunnel.frame-type = "text"
}
...

然后编写一个后台的server程序,内容如下:

c 复制代码
#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", client_socket, strerror(errno));
                close(client_socket);
                break;
            }
            else if (0 == received_len)
            {
                printf("Client [%d] disconnected!\n", client_socket);
                close(client_socket);
                break;
            }
            else
            {
                printf("Read %d bytes from client[%d] and the data is : %s\n",
                       received_len, client_socket, received_buffer);
                // Send back the received buffer to client.
                sended_len = write(client_socket, received_buffer, received_len);
                if (sended_len < 0)
                {
                    printf("wWite data back to client[%d] failed: %s \n", client_socket,
                           strerror(errno));
                    close(client_socket);
                    break;
                }
            }
        }
        sleep(1);
    }

    if (client_socket)
    {
        close(client_socket);
    }
    close(server_socket);

    return 1;
}

编译,执行程序:

c 复制代码
# gcc server1.c -o server1
# ./server1

webjs程序命名lighttpd1.4-lighttpd-1.4.76/www/websocket.js,内容如下:

js 复制代码
  // 获取按钮和文本框元素
  const sendBtn = document.getElementById('sendBtn');
  const messageBox = document.getElementById('messageBox');
  
  // 创建 WebSocket 对象
  const socket = new WebSocket('ws://127.0.0.1:8080/websocket'); // 使用一个 WebSocket 服务器进行测试
  
  // 设置 WebSocket 连接打开时的回调函数
  socket.onopen = function() {
     console.log('WebSocket 连接已打开');
  };
  
  // 设置 WebSocket 接收到消息时的回调函数
  socket.onmessage = function(event) {
     console.log('WebSocket 接收到消息:', event.data);
     messageBox.value += event.data + '\n';
  };
  
  // 设置 WebSocket 发生错误时的回调函数
  socket.onerror = function() {
     console.log('WebSocket 发生错误');
  };
  
  // 设置 WebSocket 连接关闭时的回调函数
  socket.onclose = function() {
     console.log('WebSocket 连接已关闭');
  };
  
  // 点击按钮时发送消息
  sendBtn.onclick = function() {
     const message = 'Hello, WebSocket!';
     socket.send(message);
     messageBox.value += '发送消息: ' + message + '\n';
  };

之后,可以看到端口被占用,服务器在监听:

html资源命名为lighttpd1.4-lighttpd-1.4.76/www/websocket.html,内容:

c 复制代码
<!DOCTYPE html>
<html>
<head>
   <meta charset="UTF-8">
   <title>WebSocket 示例</title>
</head>
<body>
   <button id="sendBtn">发送消息</button>
   <textarea id="messageBox" readonly></textarea>
   <script src="websocket.js"></script>
</body>
</html>

在浏览器中访问资源:

服务端收到数据:

注意:

  • 在网站: https://github.com/nori0428/mod_websocket上,有描述:DEAD.use lighttpd v1.4.46 or after w/ mod_proxy and mod_wstunnnel.,该项目已经停止维护,建议使用mod_wstunnnel了。服务器上AMI BMC的实现kvm,sol, cd-server还是在用mod_websocket

https://github.com/nori0428/mod_websocket/tree/master摘录一下数据流:

c 复制代码
client <--- ssl ---> lighttpd - mod_websocket <--- tcp ---> your websocket server

3.KVM,cd-server,sol 的实现数据分析(TBD).

相关推荐
七夜zippoe2 小时前
CANN Runtime任务描述序列化与持久化源码深度解码
大数据·运维·服务器·cann
盟接之桥3 小时前
盟接之桥说制造:引流品 × 利润品,全球电商平台高效产品组合策略(供讨论)
大数据·linux·服务器·网络·人工智能·制造
会员源码网3 小时前
理财源码开发:单语言深耕还是多语言融合?看完这篇不踩坑
网络·个人开发
米羊1214 小时前
已有安全措施确认(上)
大数据·网络
Fcy6484 小时前
Linux下 进程(一)(冯诺依曼体系、操作系统、进程基本概念与基本操作)
linux·运维·服务器·进程
袁袁袁袁满4 小时前
Linux怎么查看最新下载的文件
linux·运维·服务器
主机哥哥4 小时前
阿里云OpenClaw部署全攻略,五种方案助你快速部署!
服务器·阿里云·负载均衡
ManThink Technology5 小时前
如何使用EBHelper 简化EdgeBus的代码编写?
java·前端·网络
珠海西格电力科技6 小时前
微电网能量平衡理论的实现条件在不同场景下有哪些差异?
运维·服务器·网络·人工智能·云计算·智慧城市
默默前行的虫虫6 小时前
解决EMQX WebSocket连接不稳定及优化WS配置提升稳定性?
websocket