Skip to content

rookres/ZYNQ_webserver

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

22 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

声明:这只是为了自己学习记录所用。

如果此项目被您有幸看到,我自己认知很有局限,如果有认知偏差或者错误,还请务必用issue或PR指出,一起学习,共同进步,多谢。

前言

  这是一个自己用来练手的小Linux应用项目,采用C/C++编写。在ZYNQ7020移植上Linux系统时,想着得做些什么,只是简单的执行命令控制led灯也没意思,虽然也可以控制PL端的LED,总不像个正经的事,于是想实现个简单的项目。自己也想学习Linux编程,学习高并发等等,于是花了几周时间看书并写了几段代码(复制粘贴),实现了一个简单的webserver服务器,经验证可在含有7020板子上正常运行,放个boot启动文件夹,里面有设备树镜像之类的,rootfs太大了,就不放了。

使用方法

  

  • 直接make即可,生成的可执行文件会在build目录下。
  • 如果想在ARM上运行,需要修改makefile。默认的生成带有调试宏和-g,simpleCGI文件下的程序是x86的,想在arm下运行需要重新编译 makefile虽然添加了arm-xilinx-linux-gnueabi,但是也要有相应的Linux环境支持。
  • 如果要在电脑上运行,电脑和linux都在一个网段内,运行程序输入本地IP和端口就可以正常访问。
  • 如果是开发板的话最好连接和电脑的同一个路由器,直接看开发板ip地址就行,这样省事。如果开发版连接自己电脑,无路由,可以选择在开发板下/etc/network/interfaces目录下设置静态IP并设置电脑连接网线时ipv4属性也设置静态IP,都在一个网段内,就可以通过电脑浏览器输入开发板运行程序时的ip和port来访问了。
  • Resource文件夹下面有个PWM_JUYAN.ko驱动,还有脚本CreateBreathLeds.sh脚本,这个驱动是PS通过PL的pwm软核来输出pwm波来控制led灯来产生呼吸效果的 运行此脚本之前需要把PWM_JUYAN.ko驱动拷贝到/lib/modules/4.19.0-xilinx/目录下,然后像正常的CGI程序就可以通过网页点击运行了。

简单概述(已实现)

  • 采用epoll函数采用reactor模式来实现,采用EPOLLONESHOT和EPOLLLT模式来对Socket描述符进行操作,目前只支持GET请求。
  • 采用时间堆(小根堆)定时器对客户端连接进行活跃性检测,超时就剔除。将所有定时器中的超时时间最小的定时器的超时值作为检测超时间隔,当超时函数被调用,则必有客户端连接超时。
  • 采用半同步半反应堆的线程池(含管理线程)来处理业务,主线程负责读写,读写分开操作并使用readv/writev函数。
  • 使用有限状态机来分析HTTP请求,线程池里面的线程通过状态机分析返回值来通知主线程读写或关闭连接。
  • 支持简单的CGI程序和shell脚本。
  • 可同时处理TCP和UDP业务,UDP连接暂时只给返回相同信息,达到用户上限则会拒绝连接。

(未实现及未优化)

未实现

  • 简单的日志系统。
  • 可以处理一些post请求,并加上数据库等。
  • 应为每个用户建立内存池,内存池有上限,未达到上限前可以动态增长,到达上限后,对同一IP进行请求限制。
  • 若是在命令行用nc访问时,非正常的请求时或者请求不对时,应给客户端反射相同信息,并限制单IP的请求次数。
  • 应能判断是Linux下bin和sbin目录内的指令或者编写的CGI程序,判断是否需要参数并能进行命令参数配置。
  • 可以做个好看的界面让资源显示上面,而不是那么赤裸的显示资源,但我搞嵌入式的,这太前端了。。。。(;′⌒`)

未优化

  • 应把有限状态机里面按行解析HTTP的parse_line函数换为sscanf函数,此函数支持正则表达式,会使用更加灵活,比字符串函数好用点。
  • 应延迟关闭文件,当超过两个客户以上连接时,就会存在多次访问同一个连接的情况,最好只映射一次,并设置时间检查,超时未访问则关闭映射
  • 其实也可以让主线程只负责接受连接和监听可读可写并发送可读可写信号,用条件变量或者管道来实现,让线程池负责处理业务和读写,这样就可更快响应了。
  • 其实只有访问普通文件时,才会触发EPOLLOUT,当访问的是目录和CGI程序时,都是默认可写的,send_file函数和writev函数应该统一,最好用iovec数据指针结构体的形式,使其变长,但是CGI程序时,暂时不知道如何和EPOLLOUT结合起来,先EPOLLOUT再fork?还是fork之后的进程里再等待EPOLLOUT触发?

总结

  • 本来有libevent的库可以用,又有nginx、apache等牛逼web服务器的前提下,我觉得是有那么一点浪费时间,出力不讨好,但毕竟是为了学习嘛,经过这一折腾,让我确实学到不少东西,让我对Linux、C/C++又有许多新的认识。

  • keep learning!This is the only thing you can decide in this era!