html+php+c 实现web关灯
程序员文章站
2022-03-15 12:36:00
...
前言
一些人能够很快地学习一项新的技能并快速的进步,除了自身的努力以外常常伴有强烈的学习兴趣。一路走来,从底层硬件到应用层软件都有所接触,但却没有demo出任何有意义的小成果,十分遗憾。从本文开始,我将以自身的兴趣点出发去实现一些生活中的小demo。
远程控灯
床头有一盏台灯,每天早上出宿舍门时都得重新爬上床去关电,这样甚是麻烦。于是出现了一个远程关灯的想法。方案研究如下:
使用php
的socket接口连接linux
下的socket
。这就需要了解一点点html, js, php的东西,实测可行。
实现步骤
-
php 安装
LAMP安装,如果安装完毕不能登录网页试试重启Apache:
sudo service apache2 restart
-
php socket
html 网页编写
<!DOCTYPE html>
<html>
<head>
<title>LED Ctl</title>
<meta charset="UTF-8">
</head>
<body>
<div style="width:100%;text-align:center">
<form action="client.php?action=open" method="post">
<input type="submit" value="打开">
</form>
<br/>
<form action="client.php?action=close" method="post">
<input type="submit" value="关闭">
</form>
</div>
</body>
</html>
这里将按钮命令传递到php接口时耗费了很多时间,毕竟前端小白…
- php client 端编写
<?php
$in=$_GET['action'];
error_reporting(E_ALL);
set_time_limit(0);
$port = 2017;
$ip = "127.0.0.1";
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket < 0)
echo "socket_create() failed: reason: " . socket_strerror($socket) . "\n";
else
echo "socket create ok...\n";
echo "connect ip: '$ip' port: '$port'...\n";
$result = socket_connect($socket, $ip, $port);
if ($result < 0)
echo "connect failed.\nReason: ($result) " . socket_strerror($result) . "\n";
else
echo "connect ok...\n";
if(!socket_write($socket, $in, strlen($in)))
{
echo "socket_write() failed: reason: " . socket_strerror($socket) . "\n";
}
else
{
echo "send cmd ok...\n";
}
echo "close socket...\n";
socket_close($socket);
?>
- linux server 端编写
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h> /*标准函数库定义*/
#include <unistd.h> /*Unix 标准函数定义*/
#include <fcntl.h> /*文件控制定义*/
#include <termios.h> /*PPSIX 终端控制定义*/
#include <errno.h> /*错误号定义*/
#include <sys/types.h>
#include <sys/stat.h>
#define server_port 2017 //server本地端口
#define u8 unsigned char
static int connfd = 0;//当前建立的socke描述符
/*******************************************************************
* 名称: start_server
* 功能: 开启本地server,并进入数据接收阻塞模式(线程)
* 入口参数: func(buff,len)
buff - 接收数据缓冲区
len - 接收数据缓冲区的字节数
* 出口参数: 正确返回为0,错误返回为-1
*******************************************************************/
int start_server(void (*func)(u8 *,int))
{
//1.创建通信端点:套接字
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0)
{
perror("socket can't build");
exit(-1);
}
//设置本地地址结构体
struct sockaddr_in my_addr;
bzero(&my_addr, sizeof(my_addr)); // 清空,保证最后8字节为0
my_addr.sin_family = AF_INET; // ipv4
my_addr.sin_port = htons(server_port); // 端口
my_addr.sin_addr.s_addr = htonl(INADDR_ANY); // ip,INADDR_ANY为通配地址其值为0
//2.绑定:将本地ip、端口与套接字socket相关联起来
int err_log = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr));
if( err_log != 0)
{
perror("binding error");
close(sockfd);
exit(-1);
}
//3.监听,监听套接字改为被动,创建连接队列
err_log = listen(sockfd, 10);
if(err_log != 0)
{
perror("listen error");
close(sockfd);
exit(-1);
}
printf("listen client @port=%d...\n",server_port);
while(1)
{
struct sockaddr_in client_addr;
socklen_t cliaddr_len = sizeof(client_addr);
char cli_ip[INET_ADDRSTRLEN] = "";
u8 buff[512];//接受数据缓冲区
int len;//实际接受到的数据长度
//4.从完成连接队列中提取客户端连接
connfd = accept(sockfd, (struct sockaddr*)&client_addr, &cliaddr_len);
if(connfd < 0)
{
perror("accept error");
continue;
}
inet_ntop(AF_INET, &client_addr.sin_addr, cli_ip, INET_ADDRSTRLEN);
printf("----------------------------------------------\n");
printf("client ip=%s,port=%d\n", cli_ip,ntohs(client_addr.sin_port));
while((len=recv(connfd, buff, sizeof(buff), 0)) > 0) // 接收数据
{
(*func)((u8*)buff,len);//将接收到的数据传至函数指针
}
close(connfd); //关闭已连接套接字
printf("client closed!\n");
}
close(sockfd); //关闭监听套接字
return 0;
}
/*******************************************************************
* 名称: tcp_send_data
* 功能: server向client发送字节流
* 入口参数: buff - 发送数据缓冲区
len - 发送数据缓冲区的字节数
* 出口参数: 正确返回为0,错误返回为-1
*******************************************************************/
int tcp_send_data(u8* buff,int len)
{
if(send(connfd, buff, len, 0)<0)
{
printf("tcp send data error\n");
exit(-1);
}
return 0;
}
void myfunc(u8* buffer,int len)
{
printf("%s\n",buffer);
if(strcmp(buffer,"open")==0)
{
printf("cmd : open\n");
system("sudo ./gpio on");
}
if(strcmp(buffer,"close")==0)
{
printf("cmd : close\n");
system("sudo ./gpio off");
}
memset(buffer,0,len);
}
int main()
{
u8* buf;
int len;
start_server(myfunc);
}
- linux gpio 控制(Nanopi-T3)
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#define GPIOC_BASE_ADDRESS (0xC001C000)
#define MAP_SIZE 40
#define GPIOCOUT *(unsigned int *)base
#define GPIOCOUTENB *(unsigned int *)(base+0x04)
#define GPIOCALTFN0 *(unsigned int *)(base+0x20)
static int dev_fd;
int main(int argc, char **argv)
{
dev_fd = open("/dev/mem", O_RDWR | O_NDELAY);
if (dev_fd < 0)
{
printf("open(/dev/mem) failed.");
return 0;
}
unsigned int base = (unsigned int)mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE,
MAP_SHARED, dev_fd, GPIOC_BASE_ADDRESS );
//GPIO7-排针编号17
GPIOCALTFN0 &= ~(3<<8);
GPIOCALTFN0 |= (1<<8);
GPIOCOUTENB |= (1<<4);
if(strcmp(argv[1],"on")==0)
{
printf("turn on\n");
GPIOCOUT |= (1<<4);
}
else if(strcmp(argv[1],"off")==0)
{
printf("turn off\n");
GPIOCOUT &= ~(1<<4);
}
printf("%s\n",argv[1]);
if(dev_fd)
close(dev_fd);
munmap((unsigned int *)base,MAP_SIZE);
return 0;
}
- 拷贝
index.html client.php
到/var/www/html/
目录下,并将server
设置为开机启动。