树莓派实现自己的Qt HTTPserver
来源:互联网 发布:java 工作流引擎有哪些 编辑:程序博客网 时间:2024/06/04 19:22
1. 目标
本文以树莓派为硬件,搭建一个本地的httpserver,用于产品中的各种测试。树莓派有了httpserver后,可以跨平台访问,实现了跨平台访问硬件的目标。
2. 清单
这里列举所需要的清单:
- 2016-9-28 jessie-lite树莓派系统镜像
- Qt5+boost+opencv
- xvfb,实现后台运行带窗口的界面
- daemontool管理后台服务器
- wifi-access-point脚本,一键设置树莓派为wifi热点
3. 步骤
上述的开发环境,我已将他们全部集成到一个shell脚本中,可在httpserver下,可以一键设置好开发环境。:
1. 配置开发环境
#!/bin/bash## This version uses September 2016 rpi jessie image, please use this image#if [ "$EUID" -ne 0 ] then echo "Must be root" exitfiif [[ $# -lt 1 ]]; then echo "You need to pass a password!" echo "Usage:" echo "sudo $0 yourChosenPassword [apName]" exitfiAPPASS="$1"APSSID="rPi3"if [[ $# -eq 2 ]]; then APSSID=$2fiapt-get remove --purge hostapd -yapt-get install hostapd dnsmasq -ycat > /etc/systemd/system/hostapd.service <<EOF[Unit]Description=Hostapd IEEE 802.11 Access PointAfter=sys-subsystem-net-devices-wlan0.deviceBindsTo=sys-subsystem-net-devices-wlan0.device[Service]Type=forkingPIDFile=/var/run/hostapd.pidExecStart=/usr/sbin/hostapd -B /etc/hostapd/hostapd.conf -P /var/run/hostapd.pid[Install]WantedBy=multi-user.targetEOFcat > /etc/dnsmasq.conf <<EOFinterface=wlan0dhcp-range=10.0.0.2,10.0.0.5,255.255.255.0,12hEOFcat > /etc/hostapd/hostapd.conf <<EOFinterface=wlan0hw_mode=gchannel=10auth_algs=1wpa=2wpa_key_mgmt=WPA-PSKwpa_pairwise=CCMPrsn_pairwise=CCMPwpa_passphrase=$APPASSssid=$APSSIDEOFsed -i -- 's/allow-hotplug wlan0//g' /etc/network/interfacessed -i -- 's/iface wlan0 inet manual//g' /etc/network/interfacessed -i -- 's/ wpa-conf \/etc\/wpa_supplicant\/wpa_supplicant.conf//g' /etc/network/interfacescat >> /etc/network/interfaces <<EOF wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf# Added by rPi Access Point Setupallow-hotplug wlan0iface wlan0 inet static address 10.0.0.1 netmask 255.255.255.0 network 10.0.0.0 broadcast 10.0.0.255EOFecho "denyinterfaces wlan0" >> /etc/dhcpcd.confsystemctl enable hostapdsudo apt-get install qt5-default sudo apt-get install qtcreatorsudo apt-get install libqt5svg5* libqt5webkit5* libqt5serialport5*sudo apt-get install qtcreatorsudo apt-get install libboost1.50-allsudo apt-get install xvfbsudo apt-get install daemontools daemontools-runecho "All done! Please reboot"
2. 设置后台运行脚本
使用xvfb,可以在没有桌面系统的情况下,照样调用Qt的一些窗口库(由于应用中,要用到一些带窗口的类的功能)。调用execut.sh脚本如下:
#!/bin/shecho "Execut the service by daemontools"echo "Next will start the linebot"cd /home/pi/raspberrylinebot/build/echo "Really exec the linebot"sudo xvfb-run --server-args="-screen 0 1024x768x24" ./LineBotecho "The linebot has finish started!"
下一步就是设置daemontools来对后台程序进行管理。当后台的Qt应用程序自己当掉了,daemontools会自动在5秒后重启应用。
sudo mkdir -p /service/yourapp-sericesudo vi /service/youapp-service/runsudo chmod 755 /service/youapp-service/runcd /etc/service/sudo ln -s /service/yourapp-service .
在/service/youapp-service/run中,run是一个shell脚本,在这里调用使用exec来调用上一步骤中的execut.sh脚本。
3. 备份你的系统
使用备份脚本:
#!/bin/bashVERSION=1.5# Version 1.5 2016/09/09# * Remove any leading /dev/ from dest disk.# * Warn dest disk may be a partition if it ends with a digit.# Version 1.4 2016/03/23# * Use -F on mkfs.ext4 and avoid the question.# Version 1.3 2016/03/16# * don't > /dev/null for the mkfs.ext4 since mkfs can ask a question# Version 1.2 2015/02/17# * add -x option# * tweak some echo messages# Version 1.1 2015/02/16# * Do not include dphys swapfile in the clone.# * Add a missing -s flag to one of the parted commands.# * Dump parted stderr to /dev/null since it now complains about destination# disk partitions ending outside of disk before I get chance to resize# the partitions.# * Strip trailing s from PART_START - (fdisk now doesn't seem to accept...)#PGM=`basename $0`RSYNC_OPTIONS="--force -rltWDEgopt"# List of extra dirs to create under /mnt.OPTIONAL_MNT_DIRS="clone mnt sda sdb rpi0 rpi1"# Where to mount the disk filesystems to be rsynced.CLONE=/mnt/cloneCLONE_LOG=/var/log/$PGM.logHOSTNAME=`hostname`SRC_BOOT_PARTITION_TYPE=`parted /dev/mmcblk0 -ms p | grep "^1" | cut -f 5 -d:`SRC_ROOT_PARTITION_TYPE=`parted /dev/mmcblk0 -ms p | grep "^2" | cut -f 5 -d:`if [ `id -u` != 0 ]then echo -e "$PGM needs to be run as root.\n" exit 1fiif ! rsync --version > /dev/nullthen echo -e "\nOoops! rpi-clone needs the rsync program but cannot find it." echo "Make sure rsync is installed:" echo " $ sudo apt-get update" echo -e " $ sudo apt-get install rsync\n" exit 0fiif test -e /sbin/fsck.vfatthen HAVE_FSCK_VFAT="yes"else echo "[Note] fsck.vfat was not found." echo "It is recommended to install dosfstools:" echo " $ sudo apt-get update" echo " $ sudo apt-get install dosfstools"fiusage() { echo "" echo "usage: $PGM sdN {-f|--force-initialize} {-v|--verbose} {-x}" echo " Example: $PGM sda" echo " -v - list all files as they are copied." echo " -f - force initialize the destination partitions" echo " -x - use set -x for very verbose bash shell script debugging" echo "" echo " Clone (rsync) a running Raspberry Pi file system to a destination" echo " SD card 'sdN' plugged into a Pi USB port (via a USB card reader)." echo " $PGM can clone the running system to a new SD card or can" echo " incrementally rsync to existing backup Raspberry Pi SD cards." echo "" echo " If the destination SD card has an existing $SRC_BOOT_PARTITION_TYPE partition 1 and a" echo " $SRC_ROOT_PARTITION_TYPE partition 2, $PGM assumes (unless using the -f option)" echo " that the SD card is an existing backup with the partitions" echo " properly sized and set up for a Raspberry Pi. All that is needed" echo " is to mount the partitions and rsync them to the running system." echo "" echo " If these partitions are not found (or -f), then $PGM will ask" echo " if it is OK to initialize the destination SD card partitions." echo " This is done by a partial 'dd' from the running booted device" echo " /dev/mmcblk0 to the destination SD card /dev/sdN followed by a" echo " fdisk resize and mkfs.ext4 of /dev/sdN partition 2." echo " This creates a completed $SRC_BOOT_PARTITION_TYPE partition 1 containing all boot" echo " files and an empty but properly sized partition 2 rootfs." echo " The SD card partitions are then mounted and rsynced to the" echo " running system." echo "" echo " The SD card destination partitions will be mounted on $CLONE." echo " A log will be written to $CLONE_LOG." echo " It's better to avoid running other disk writing programs" echo " when running $PGM." echo "" echo " Version $VERSION" exit 0 }VERBOSE=offwhile [ "$1" ]do case "$1" in -v|--verbose) VERBOSE=on RSYNC_OPTIONS=${RSYNC_OPTIONS}v ;; -f|--force-initialize) FORCE_INITIALIZE=true ;; -x) set -x ;; -h|--help) usage ;; *) if [ "$DST_DISK" != "" ] then echo "Bad args" usage fi DST_DISK=$1 ;; esac shiftdoneif [ "$DST_DISK" = "" ]then usage exit 0fi# Remove leading /dev/DIR=`expr substr $DST_DISK 1 5`if [ "$DIR" == "/dev/" ]then DST_DISK=${DST_DISK#/dev/}fiif ! cat /proc/partitions | grep -q $DST_DISKthen echo "Destination disk '$DST_DISK' does not exist." echo "Plug the destination SD card into a card reader connected to a" echo "USB port. If it does not show up as '$DST_DISK', then do a" echo -e "'cat /proc/partitions' to see where it might be.\n" exit 0fiCHK_DISK=`cat /proc/partitions | grep -m 1 $DST_DISK`D=${CHK_DISK: -1}if [ "$D" -eq "$D" ] 2>/dev/nullthen echo " The target disk you entered, $DST_DISK, ends with a digit and this" echo " may mean you have given a partition name instead of a disk name." echo " For example, if you want to clone to a disk sda," echo " specify sda and not one of its partition names like sda1 or sda2." echo -n "Do you want to continue anyway? (yes/no):" read resp if [ "$resp" != "y" ] && [ "$resp" != "yes" ] then echo "" exit 0 fifiunmount_or_abort() { echo -n "Do you want to unmount $1? (yes/no): " read resp if [ "$resp" = "y" ] || [ "$resp" = "yes" ] then if ! umount $1 then echo "Sorry, $PGM could not unmount $1." echo -e "Aborting!\n" exit 0 fi else echo -e "Aborting!\n" exit 0 fi }DST_ROOT_PARTITION=/dev/${DST_DISK}2DST_BOOT_PARTITION=/dev/${DST_DISK}1# Check that none of the destination partitions are busy (mounted).#DST_ROOT_CURMOUNT=`fgrep "$DST_ROOT_PARTITION " /etc/mtab | cut -f 2 -d ' ' `DST_BOOT_CURMOUNT=`fgrep "$DST_BOOT_PARTITION " /etc/mtab | cut -f 2 -d ' ' `if [ "$DST_ROOT_CURMOUNT" != "" ] || [ "$DST_BOOT_CURMOUNT" != "" ]then echo "A destination partition is busy (mounted). Mount status:" echo " $DST_ROOT_PARTITION: $DST_ROOT_CURMOUNT" echo " $DST_BOOT_PARTITION: $DST_BOOT_CURMOUNT" if [ "$DST_BOOT_CURMOUNT" != "" ] then unmount_or_abort $DST_BOOT_CURMOUNT fi if [ "$DST_ROOT_CURMOUNT" != "" ] then unmount_or_abort $DST_ROOT_CURMOUNT fifiTEST_MOUNTED=`fgrep " $CLONE " /etc/mtab | cut -f 1 -d ' ' `if [ "$TEST_MOUNTED" != "" ]then echo "This script uses $CLONE for mounting filesystems, but" echo "$CLONE is already mounted with $TEST_MOUNTED." unmount_or_abort $CLONE fiif [ ! -d $CLONE ]then MNT_MOUNT=`fgrep " /mnt " /etc/mtab | cut -f 1 -d ' ' ` if [ "$MNT_MOUNT" = "" ] then mkdir $CLONE else echo "$MNT_MOUNT is currently mounted on /mnt." unmount_or_abort /mnt mkdir $CLONE fifi# Borrowed from do_expand_rootfs in raspi-configexpand_rootfs() { # Get the starting offset of the root partition # (with Jessie's parted, now need to strip trailing 's' from PART_START) PART_START=$(parted /dev/mmcblk0 -ms unit s p \ | grep "^2" | cut -f 2 -d: | cut -f 1 -d s) [ "$PART_START" ] || return 1 # Return value will likely be error for fdisk as it fails to reload the # partition table because the root fs is mounted fdisk /dev/$DST_DISK > /dev/null <<EOFpd2np2$PART_STARTpwqEOF }# =========== Disk Setup and Checks ===========## Check that destination partitions are the right type.#DST_BOOT_PARTITION_TYPE=`parted /dev/$DST_DISK -ms p 2>/dev/null \ | grep "^1" | cut -f 5 -d:`DST_ROOT_PARTITION_TYPE=`parted /dev/$DST_DISK -ms p 2>/dev/null \ | grep "^2" | cut -f 5 -d:`CLONE_MODE="rsync modified files to existing $DST_DISK file systems"if [ "$DST_BOOT_PARTITION_TYPE" != "$SRC_BOOT_PARTITION_TYPE" ] || \ [ "$DST_ROOT_PARTITION_TYPE" != "$SRC_ROOT_PARTITION_TYPE" ] || \ [ "$FORCE_INITIALIZE" = "true" ]then CLONE_MODE="rsync all files to $DST_DISK root file system" echo "" if [ "$FORCE_INITIALIZE" = "true" ] then echo "Forcing a partition initialization of destination disk $DST_DISK" else echo "The destination disk $DST_DISK partition table does not" echo "match the booted disk /dev/mmcblk0 partition table so a" echo "destination disk initialize is required." fi echo "The existing destination disk '$DST_DISK' partitions are:" parted /dev/$DST_DISK -s unit MB p 2>/dev/null \ | sed "/^Model/d ; /^Sector/d ; /^Disk Flags/d"# if [ "$DST_BOOT_PARTITION_TYPE" != "$SRC_BOOT_PARTITION_TYPE" ]# then# echo -e " ... Cannot find a destination boot file system of type: $SRC_BOOT_PARTITION_TYPE\n"# fi# if [ "$DST_ROOT_PARTITION_TYPE" != "$SRC_ROOT_PARTITION_TYPE" ]# then# echo -e " ... Cannot find a destination root file system of type: $SRC_ROOT_PARTITION_TYPE\n"# fi echo "*** All data on destination disk $DST_DISK will be overwritten! ***" echo "" echo -n "Do you want to initialize the destination disk /dev/$DST_DISK? (yes/no): " read resp if [ "$resp" = "y" ] || [ "$resp" = "yes" ] then # Image onto the destination disk a beginning fragment of the # running SD card file structure that spans at least more than # the start of partition 2. # # Calculate the start of partition 2 in MB for the dd. PART2_START=$(parted /dev/mmcblk0 -ms unit MB p | grep "^2" \ | cut -f 2 -d: | sed s/MB// | tr "," "." | cut -f 1 -d.) # and add some slop DD_COUNT=`expr $PART2_START + 8` echo "" echo "Imaging the partition structure, copying $DD_COUNT megabytes..." sync dd if=/dev/mmcblk0 of=/dev/$DST_DISK bs=1M count=$DD_COUNT # Partition was copied live so fsck to clean up for possible future # "Volume was not properly unmounted" warnings. if [ "$HAVE_FSCK_VFAT" = "yes" ] then echo "Running fsck on $DST_BOOT_PARTITION..." fsck -p $DST_BOOT_PARTITION &> /dev/null fi # But, though Partion 1 is now imaged, partition 2 is incomplete and # maybe the wrong size for the destination SD card. So fdisk it to # make it fill the rest of the disk and mkfs it to clean it out. # echo "Sizing partition 2 (root partition) to use all SD card space..." expand_rootfs mkfs.ext4 -F $DST_ROOT_PARTITION echo "" echo "/dev/$DST_DISK is initialized and resized. Its partitions are:"# fdisk -l /dev/$DST_DISK | grep $DST_DISK parted /dev/$DST_DISK unit MB p \ | sed "/^Model/d ; /^Sector/d ; /^Disk Flags/d" SRC_ROOT_VOL_NAME=`e2label /dev/mmcblk0p2` echo "" echo "Your booted /dev/mmcblk0p2 rootfs existing label: $SRC_ROOT_VOL_NAME" echo -n "You may enter a label for the destination rootfs $DST_ROOT_PARTITION: " read resp if [ "$resp" != "" ] then e2label $DST_ROOT_PARTITION $resp fi else echo -e "Aborting\n" exit 0 fifi# =========== Setup Summary ===========#DST_ROOT_VOL_NAME=`e2label $DST_ROOT_PARTITION`if [ "$DST_ROOT_VOL_NAME" = "" ]then DST_ROOT_VOL_NAME="no label"fiecho ""echo "======== Clone Summary ========"echo "Clone mode : $CLONE_MODE"echo "Clone destination disk : $DST_DISK"echo "Clone destination rootfs : $DST_ROOT_PARTITION ($DST_ROOT_VOL_NAME) on ${CLONE}"echo "Clone destination bootfs : $DST_BOOT_PARTITION on ${CLONE}/boot"echo "Verbose mode : $VERBOSE"echo "==============================="# If this is an SD card initialization, can watch progress of the clone# in another terminal with: watch df -h#echo -n "Final check, is it Ok to proceed with the clone (yes/no)?: "read respif [ "$resp" != "y" ] && [ "$resp" != "yes" ]then echo -e "Aborting the disk clone.\n" exit 0fi## =========== End of Setup ===========# Mount destination filesystems.echo "=> Mounting $DST_ROOT_PARTITION ($DST_ROOT_VOL_NAME) on $CLONE"if ! mount $DST_ROOT_PARTITION $CLONEthen echo -e "Mount failure of $DST_ROOT_PARTITION, aborting!\n" exit 0fiif [ ! -d $CLONE/boot ]then mkdir $CLONE/bootfiecho "=> Mounting $DST_BOOT_PARTITION on $CLONE/boot"if ! mount $DST_BOOT_PARTITION $CLONE/bootthen umount $CLONE echo -e "Mount failure of $DST_BOOT_PARTITION, aborting!\n" exit 0fiecho "==============================="# Do not include a dhpys swapfile in the clone. dhpys-swapfile will# regenerate it at boot.#if [ -f /etc/dphys-swapfile ]then SWAPFILE=`cat /etc/dphys-swapfile | grep ^CONF_SWAPFILE | cut -f 2 -d=` if [ "$SWAPFILE" = "" ] then SWAPFILE=/var/swap fi EXCLUDE_SWAPFILE="--exclude $SWAPFILE"fiSTART_TIME=`date '+%H:%M:%S'`# Exclude fuse mountpoint .gvfs, various other mount points, and tmpfs# file systems from the rsync.#syncecho "Starting the filesystem rsync to $DST_DISK"echo -n "(This may take several minutes)..."rsync $RSYNC_OPTIONS --delete \ $EXCLUDE_SWAPFILE \ --exclude '.gvfs' \ --exclude '/dev' \ --exclude '/media' \ --exclude '/mnt' \ --exclude '/proc' \ --exclude '/run' \ --exclude '/sys' \ --exclude '/tmp' \ --exclude 'lost\+found' \ // \ $CLONE# Fixup some stuff#for i in dev media mnt proc run sysdo if [ ! -d $CLONE/$i ] then mkdir $CLONE/$i fidoneif [ ! -d $CLONE/tmp ]then mkdir $CLONE/tmp chmod a+w $CLONE/tmpfi# Some extra optional dirs I create under /mntfor i in $OPTIONAL_MNT_DIRSdo if [ ! -d $CLONE/mnt/$i ] then mkdir $CLONE/mnt/$i fidonerm -f $CLONE/etc/udev/rules.d/70-persistent-net.rulesDATE=`date '+%F %H:%M'`echo "$DATE $HOSTNAME $PGM : clone to $DST_DISK ($DST_ROOT_VOL_NAME)" \ >> $CLONE_LOGecho "$DATE $HOSTNAME $PGM : clone to $DST_DISK ($DST_ROOT_VOL_NAME)" \ >> $CLONE/$CLONE_LOGSTOP_TIME=`date '+%H:%M:%S'`echo ""echo "*** Done with clone to /dev/$DST_DISK ***"echo " Started: $START_TIME Finished: $STOP_TIME"echo ""# Pause before unmounting in case I want to inspect the clone results# or need to custom modify any files on the destination SD clone.# Eg. modify $CLONE/etc/hostname, $CLONE/etc/network/interfaces, etc# if I'm cloning into a card to be installed on another Pi.#echo -n "Hit Enter when ready to unmount the /dev/$DST_DISK partitions..."read respecho "unmounting $CLONE/boot"umount $CLONE/bootecho "unmounting $CLONE"umount $CLONEecho "==============================="exit 0
阅读全文
0 0
- 树莓派实现自己的Qt HTTPserver
- java自己实现的httpserver
- python3实现的多线程httpserver
- HttpServer的简单实现_Java
- android端HttpServer的实现
- Qt实现自己的IDE
- 简单剖析一下 HttpServer的实现方式
- 使用nio实现简单的httpServer
- 利用Httplistener实现的HttpServer类
- socket实现一个简单的httpserver
- Nancy HttpServer---自己开发HttpServer (不断更新中)
- 如何开发自己的HttpServer-NanoHttpd源码解读
- 如何开发自己的HttpServer-NanoHttpd源码解读
- 简易http服务器的实现(实现)httpserver.c
- netty 简单httpserver实现
- 用libevent实现httpserver
- Java HttpServer实现交互
- 内置jetty实现Httpserver
- wstring写文件
- 事务控制语言(DTL)
- 用==0判断偶数不用!=1判断偶数
- 360漏洞修复卡在正在安装的解决方法
- Java多线程系列--“JUC线程池”01之 线程池架构
- 树莓派实现自己的Qt HTTPserver
- Python爬虫实例——基于BeautifulSoup和requests实现
- 主流监督式机器学习分类算法
- ReactNative系列之十六listview中子元素变更checkbox
- cmake升级之后遇到的cmake问题的解决方案
- Java多线程系列--“JUC线程池”02之 线程池原理(一)
- 你真的了解head标签下的meta?
- Establishing SSL
- u3d计算向量间夹角