lighttpd以及socket和WebSocket编程

综述

本文涉及到下图绿色背景部分的内容:

在这里插入图片描述

左侧位于Linux下,其中包括lighttpd和socket程序;右侧是WebSocket程序。两者通过网络交互。

本文介绍lighttpd的基本使用方式,并通过编程完成一个socket服务器与浏览器端的WebSocket客户端通信。

lighttpd

首先介绍lighttpd,因为它是后端(socket程序)和前端(WebSocket程序)交互的基础。

lighttpd是一款轻量级的开源Web服务器,跟Apache、Nginx功能差不多,对应的官网http://www.lighttpd.net/。

lighttpd目前只支持Linux,所以这里在虚拟机(安装Ubuntu20.04版本)上编译和使用lighttpd,对应的Linux版本:

jw@ubuntu:~/code/www/html$ uname -a
Linux ubuntu 5.15.0-82-generic #91~20.04.1-Ubuntu SMP Fri Aug 18 16:24:39 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux

下载lighttpd最新版本,获取到lighttpd-1.4.71.tar.gz。

  1. 首先解压缩源代码:
jw@ubuntu:~/code$ tar -xzvf lighttpd-1.4.71.tar.gz
  1. 安装依赖程序:
jw@ubuntu:~/code/lighttpd-1.4.71$ sudo apt install zlib1g-dev libpcre2-dev
  1. 进入解压缩得到的目录,然后进行configure:
jw@ubuntu:~/code/lighttpd-1.4.71$ ./configure --prefix=/usr/local/lighttpd
  1. 编译:
jw@ubuntu:~/code/lighttpd-1.4.71$ make
  1. 安装:
jw@ubuntu:~/code/lighttpd-1.4.71$ sudo make install

安装的位置是/usr/local/lighttpd/

w@ubuntu:~/code/lighttpd-1.4.71$ ls -al /usr/local/lighttpd/
total 20
drwxr-xr-x  5 root root 4096 Sep  3 07:03 .
drwxr-xr-x 11 root root 4096 Sep  3 07:03 ..
drwxr-xr-x  2 root root 4096 Sep  3 07:03 lib
drwxr-xr-x  2 root root 4096 Sep  3 07:03 sbin
drwxr-xr-x  3 root root 4096 Sep  3 07:03 share
  1. 进入到lighttpd所在的目录,后续以root进行操作:
root@ubuntu:/usr/local/lighttpd/sbin# ll
total 1992
drwxr-xr-x 2 root root    4096 Sep  3 07:03 ./
drwxr-xr-x 5 root root    4096 Sep  3 07:03 ../
-rwxr-xr-x 1 root root 2004088 Sep  3 07:03 lighttpd*
-rwxr-xr-x 1 root root   23048 Sep  3 07:03 lighttpd-angel*
  1. 为了使用lighttpd,需要有配置文件,下面是一个最简单的例子(test.conf):
server.document-root = "/home/jw/code/www/html"
server.port = 80
mimetype.assign = (".html" => "text/html",".txt" => "text/plain",".jpg" => "image/jpeg",".png" => "image/png"
)
index-file.names = ( "index.html" )

简单说明它们的意义:

  • server.document-root:指定了Web服务器目录,我们需要在这里放浏览器可以访问的文件,比如html文件。
  • server.port:指定端口,默认非安全的Web服务器端口是80。
  • mimetype.assign:指定支持的文件。
  • index-file.names:指定入口文件。
  1. server.document-root指定的目录中存放html文件,下面是一个例子(index.html ):
<html><body>Hello Wolrd!</body>
</html>

当通过浏览器登录服务器时,首先访问到的就是这个文件。

启动lighttpd的应用程序的命令如下:

root@ubuntu:/usr/local/lighttpd/sbin# ./lighttpd -D -f test.conf 
2023-09-03 07:17:49: (server.c.1909) server started (lighttpd/1.4.71)

启动之后该服务器会持续运行,此时可以查看到网络状态:

root@ubuntu:/usr/local/lighttpd/sbin# netstat -ntlv
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN     
tcp6       0      0 ::1:631                 :::*                    LISTEN 

这里显示的第一行对应的就是lighttpd服务器,它监听80端口,IP显示全0表示没有限制。

通过浏览器访问lighttpd服务器,输入的IP就是Linux系统的IP,端口可以不写,默认就是80。测试结果如下图所示:

在这里插入图片描述

到这里一个简单的lighttpd服务器就已经开启了。

当然这只是一个开始,此时浏览器只能访问lighttpd中的简单html文件,要想要打通后端的socket程序和前端的WebSocket程序,还需要依赖于lighttpd的ws_tunnel插件。为了使lighttpd支持WebSocket,需要修改它的配置,以下是修改之后的test.conf :

server.modules += ("mod_wstunnel"
)server.document-root = "/home/jw/code/www/html"
server.port = 80
mimetype.assign = (".html" => "text/html",".txt" => "text/plain",".jpg" => "image/jpeg",".png" => "image/png"
)
static-file.exclude-extensions = ( ".fcgi", ".php", ".rb", "~", ".inc" )
index-file.names = ( "index.html" )$HTTP["url"] =~ "^/websocket.test" {wstunnel.server = ("" => (("host" => "127.0.0.1","port" => "888")))wstunnel.frame-type = "text"
}

这里的改动有以下的几个:

  • 通过server.modules引入lighttpd插件,在lighttpd中,通过插件的方式可以引入很多新的特性,比如这里的WebSocket(对应插件mod_wstunnel),还有CGI,代理,等等。

  • 配置wstunnel,所有的参数可以在Docs ConfigurationOptions - Lighttpd - lighty labs找到,这里的配置主要针对特定格式的WebSocket,其配置有两个:一个是转发的地址和端口,指向了localhost(127.0.0.1)和888端口,注意它们需要跟Linux端的服务器有相同的配置,否则无法转发到指定的处理程序;另一个是WebSocket的数据格式,这里指定的是文本格式。

配置修改之后重新打开lighttpd:

root@ubuntu:/usr/local/lighttpd/sbin# ./lighttpd -D -f test.conf 
2023-09-09 22:20:15: (server.c.1909) server started (lighttpd/1.4.71)

socket编程

编写Linux端的服务器程序,下面是一个示例:

#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 888
// 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;
}

这里使用了socket编程,注意socket和前面提到的WebSocket虽然都用来网络通信,但是它们不是同一个东西,关于它们的具体差别涉及到socket和WebSocket的基础,这里不展开。

这个程序的实现很简单,就是将服务器获取到的数据直接返回给发送端。编译和使用该程序:

root@ubuntu:/home/jw/code/www/html# gcc websocket_server.c 
root@ubuntu:/home/jw/code/www/html# ./a.out 
Socket[3] has bond on port[888] for IP address[127.0.0.1]!
Waiting and accept new client connect...

再次查看网络状态:

root@ubuntu:/usr/local/lighttpd/sbin# netstat -ntlv
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:888           0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN     
tcp6       0      0 ::1:631                 :::*                    LISTEN 

可以看到多监听了一个端口888,IP是localhost(127.0.0.1),由于ligtttpd的配置,前端连接过来的特定WebSocket(满足^/websocket.test的格式)就会被本程序处理。

WebSocket程序

本节介绍浏览器端代码的编写。

前面的两步都在Linux系统中(这里使用了虚拟机中的Ubuntu系统),而这里的操作可以在任意的系统中使用,只要存在浏览器,且跟Linux系统可以通过网络通信即可。不过编写的程序还是在Linux系统中,且在lighttpd指定的目录下,其示例代码(index.html):

<h1>Websocket Test</h1>
<pre id="messages" style="height: 400px; overflow: scroll"></pre>
<input type="text" id="messageBox" placeholder="Type your message here"style="display: block; width: 100%; margin-bottom: 10px; padding: 10px;" />
<button id="send" title="Send Message!" style="width: 100%; height: 30px;">Send Message</button><script>(function () {const sendBtn = document.querySelector('#send');const messages = document.querySelector('#messages');const messageBox = document.querySelector('#messageBox');let ws;function showMessage(message) {messages.textContent += `\nReceived: ${message}`;messages.scrollTop = messages.scrollHeight;messageBox.value = '';}function init() {if (ws) {ws.onerror = ws.onopen = ws.onclose = null;ws.close();}ws = new WebSocket("ws://" + location.host + "/websocket.test");ws.onopen = () => {console.log('Connection opened!');}ws.onmessage = ({ data }) => showMessage(data);ws.onclose = function () {console.log('Connectino closed!');ws = null;}}sendBtn.onclick = function () {if (!ws) {showMessage("No WebSocket connection :(");return;}ws.send(messageBox.value);console.log("Sended: " + messageBox.value);}init();})();
</script>

注意这里的:

ws = new WebSocket("ws://" + location.host + "/websocket.test");

location.host对应的是Linux的IP,整个URL满足lighttpd中ws_tunnel的转发要求,所以会被第二步中的程序接收到。

通过浏览器访问location.host对应的地址,执行结果如下:

在这里插入图片描述

图中的虚拟机安装有Ubuntu20.04,开启两个进程,上面的是lighttpd作为Web服务器,下面是socket编写的服务器程序;虚拟机外面是浏览器,输入Ubuntu20.04系统的IP即可访问lighttpd,并显示指定目录下的index.html文件,在该界面下输入的内容会被lighttpd传递给服务器程序,而后者打印传递过来的内容然后返回,最后在浏览器显示出来。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/134690.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot @Value读不到Nacos配置中心的值。(properties配置文件)

读不到配置中心的值&#xff0c; 配置中心的配置文件名字&#xff08;Data ID的值&#xff09;要以.properties结尾。 如果是yaml&#xff0c;就以yaml命名。

Git:Git的一些基本操作

文章目录 基本认识使用方法创建本地仓库配置本地仓库 工作区、暂存区、版本库的概念添加文件版本回退撤销修改删除操作 基本认识 首先要对Git有一个基本的认知&#xff1a; Git本质上是一个版本控制器&#xff0c;可以对一个信息的多个版本进行一些控制&#xff0c;而能对版本…

腾讯mini项目-【指标监控服务重构】2023-08-16

今日已办 v1 验证 StageHandler 在处理消息时是否为单例&#xff0c;【错误尝试】 type StageHandler struct { }func (s StageHandler) Middleware1(h message.HandlerFunc) message.HandlerFunc {return func(msg *message.Message) ([]*message.Message, error) {log.Log…

mac 本地运行 http-proxy-middleware ,请求超时

const http require(http)"/customer": {target: "http://10.10.111.192:8080/",// target: "http://user.jinfu.baohan.com/",changeOrigin: true, // 是否启用跨域// 解决mac 代理超时问题headers: {Connection: "keep-alive"},// …

脚本:python绘制七夕爱心

文章目录 效果脚本Reference 效果 脚本 import random from math import sin, cos, pi, log from tkinter import *CANVAS_WIDTH 640 # 画布的宽 CANVAS_HEIGHT 640 # 画布的高 CANVAS_CENTER_X CANVAS_WIDTH / 2 # 画布中心的X轴坐标 CANVAS_CENTER_Y CANVAS_HEIGHT /…

WebGL 根据模型矩阵的逆转置矩阵计算运动物体的光照效果

目录 前言 坐标变换引起法向量变化 变化规律&#xff1a; 魔法矩阵&#xff1a;逆转置矩阵 逆转置矩阵的用法总结 Matrix4对象的 setInverseOf 、transpose 方法规范&#xff08;以完成逆转置矩阵&#xff09; 示例代码&#xff08;LightedTranslatedRotatedCube.js&am…

前端JavaScript入门到精通,javascript核心进阶ES6语法、API、js高级等基础知识和实战 —— JS基础(二)

人生是旷野&#xff0c;不是轨道。 思维导图 一、运算符 1.1 赋值运算符 1.2 一元运算符 1.3 比较运算符 1.4 逻辑运算符 逻辑与&#xff0c;一假则假 逻辑或&#xff0c;一真则真 <!DOCTYPE html> <html lang"en"><head><meta charset&quo…

win10远程桌面控制Ubuntu服务器 - 内网穿透实现公网远程

文章目录 前言视频教程1. ubuntu安装XRDP2.局域网测试连接3. Ubuntu安装cpolar内网穿透4.cpolar公网地址测试访问5.固定域名公网地址 转载自cpolar极点云文章&#xff1a;树莓派使用Nginx 搭建轻量级网站远程访问 前言 XRDP是一种开源工具&#xff0c;它允许用户通过Windows R…

【力扣周赛】第 362 场周赛(⭐差分匹配状态压缩DP矩阵快速幂优化DPKMP)

文章目录 竞赛链接Q1&#xff1a;2848. 与车相交的点解法1——排序后枚举解法2——差分数组⭐差分数组相关题目列表&#x1f4d5;1094. 拼车1109. 航班预订统计2381. 字母移位 II2406. 将区间分为最少组数解法1——排序贪心优先队列解法2——差分数组 2772. 使数组中的所有元素…

Java 高频疑难问题系列一

​​​​​​​ 目录 ​编辑​​​​​​​ 1.零长度 2.redis的有序集的排序 3.Unsafe类 4.带资源的try语句 5.Spring如何实现计划任务 6.Java中普通代码块,构造代码块,静态代码块执行顺序 7.MyBatis缓存机制 8.Redis Java 2种类型操作转换 9.CAS底层原理和问题 1…

无涯教程-JavaScript - AGGREGATE函数

描述 返回列表或数据库中的聚合。 AGGREGATE函数可以将不同的聚合函数应用于列表或数据库,并且可以选择忽略隐藏的行和错误值。 AGGREGATE函数具有两种不同的格式- 参考格式数组格式 参考格式 语法 AGGREGATE (function_num, options, ref1, [ref2] …)争论 Argument描述…

【学习笔记】Java 一对一培训(2.1)Java基础语法

【学习笔记】Java 一对一培训&#xff08;2.1&#xff09;Java基础语法 关键词&#xff1a;Java、Spring Boot、Idea、数据库、一对一、培训、教学本文主要内容含Java简介、Java基础语法、Java对象和类、Java基本数据类型、Java变量类型、Java修饰符计划2小时完成&#xff0c;…

机器学习:PCA(Principal Component Analysis主成分)降维

参考&#xff1a;PCA降维原理 操作步骤与优缺点_TranSad的博客-CSDN博客 PCA降维算法_偶尔努力翻身的咸鱼的博客-CSDN博客 需要提前了解的数学知识&#xff1a; 一、PCA的主要思想 PCA&#xff0c;即主成分分析方法&#xff0c;是一种使用最广泛的数据降维算法。PCA的主要思想…

【计算机视觉】Vision and Language Pre-Trained Models算法介绍合集(一)

文章目录 一、ALIGN二、Contrastive Language-Image Pre-training&#xff08;CLIP&#xff09;三、Learning Cross-Modality Encoder Representations from Transformers&#xff08;LXMERT&#xff09;四、BLIP: Bootstrapping Language-Image Pre-training五、Vision-and-La…

带你进入桌面数控机床金工实训室

桌面型数控车床实训室 你知道中国哪所大学金工实训室拥有多的小型数控机床吗&#xff1f;答案是安徽工程大学。其国际工程师学院里面建了一栋新楼&#xff0c;专门分配了4个独立的房间作为实训室&#xff0c;占地300平方米&#xff0c;分别配置了小型数控车床&#xff0c;小型…

ES6中新增加的Symbol数据类型及其使用场景

聚沙成塔每天进步一点点 ⭐ 专栏简介在这里插入图片描述 ⭐ ES6中的Symbol数据类型⭐ 对象属性名称⭐ 防止属性冲突⭐ 内置Symbols⭐ 迭代器和生成器⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航…

chatgpt综述和报告

ChatGPT究竟强在哪&#xff1f;复旦大学邱锡鹏教授《大型语言模型的能力分析与应用》_哔哩哔哩_bilibili2022年底&#xff0c;美国OpenA1公司发布了ChatGPT&#xff0c;一个可以与人类对话交互的千亿规模参数的大型语言模型。它可以根据用户输入的指令完成各种语言相关的任务&a…

电商API的应用价值:淘宝1688京东API接口系列

API接口是一种软件应用程序&#xff0c;它充当两个不同软件应用程序之间的中介。它帮助不同的应用程序相互通信&#xff0c;共享数据&#xff0c;从而使用户能够完成不同的任务。API接口的用途非常广泛&#xff0c;下面是一些常见的用途&#xff1a; 数据共享&#xff1a;API接…

ChatGPT在职业规划中的智能助手

随着科技的不断发展&#xff0c;人工智能&#xff08;AI&#xff09;正逐渐成为我们日常生活的一部分。ChatGPT作为一种智能语言模型&#xff0c;可以在职业规划中充当智能助手的角色。本文将探讨ChatGPT在职业规划中的应用&#xff0c;以及它如何成为未来工作的智能伙伴。 首先…

2020-2023中国高等级自动驾驶产业发展趋势研究-中国高等级自动驾驶发展近况

1.2 中国高等级自动驾驶发展近况 通过对中国高等级自动驾驶行业的观察和分析&#xff0c;亿欧汽车认为&#xff0c;除技术解决方案提供商外&#xff0c;如今的车企、政府、资本同样在产业链中扮演重要角色。此外&#xff0c;车路协同技术的发展也为高等级自动驾驶的发展提供了更…