热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

用树莓派改装电风扇及实现Android遥控

最近天气很热,我租的房子又没有空调,基本上风扇一开就是一晚上,结果经常起床后发现口干舌燥的。我觉得这肯定是因为整晚吹风扇搞的,

最近天气很热,我租的房子又没有空调,基本上风扇一开就是一晚上,结果经常起床后发现口干舌燥的。我觉得这肯定是因为整晚吹风扇搞的,不管是不是,反正我觉得就是了。不开风扇吧,热!开风扇吧,早上起来不舒服,怎么办呢?能不能让风扇吹一会停一会这样的吹呢?让手机来当遥控器来控制风扇?加上语音控制?我看了下我那吃灰半年多的树莓派,觉得应该让它动一动了。

硬件准备

首先,电扇是必须的,树莓派吃灰了半年,也该工作工作了。其他再需要啥的就该淘宝了。树莓派控制电扇嘛,3v-7v直流信号控制220v交流的电磁继电器得一个。连接树莓派和继电器的杜邦线若干,连接电风扇和继电器得卡口一对,注意需要能承受住风扇的电流的,不要太细的。其他的以后再说吧!
东西准备好后,先连接电路。PO上几张图,不用好看,只要能说明问题。
拆掉底座后,图是这样的,左边是定时的,坏了定不了。右边是调速的。把调速的电源线断开,接到继电器得被控端。使用继电器的常闭触点,就是把树莓派拿掉,风扇和原来一样用。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

从代码看也比较简单,使用GPIO05来控制风扇,默认设置为低电平。低电平的时候,继电器常闭,风扇的开关打开,风扇就转。高电平的时候,继电器的常闭触点断开,风扇开关打开的时候,风扇也不转了。输入open的时候,05脚设置为低电平,风扇打开。输入close的时候,05脚设置高电平,风扇停止。

实现定时功能

做这个的初衷就是让风扇定时开一会儿关一会儿,所以能控制风扇后,第一时间自然就是把这个功能给实现掉了。用python来实现,代码自然简单的不能再简单了:

#-*- coding: utf-8 -*-
from SmartServer import SmartServer
import threading
import RPi.GPIO as GPIOfanState=[1]# gpio初始化
def gpioInit():GPIO.setmode(GPIO.BCM)GPIO.setup(5,GPIO.OUT,initial=GPIO.HIGH)# 风扇是GPIO02
def switchFan(open=[0]):fanState[0]= 1 if not open[0] else 0GPIO.output(5,fanState[0])print('fan close' if fanState[0] else 'fan open')# 定时任务,默认十五分钟执行一次
def timerCheck(time=60*15,func=0,args=()):if func:func(args)timer=threading.Timer(time,timerCheck,(time,func,args))timer.start()if __name__ == "__main__":gpioInit()# 十五分钟反转一下GPIO,开启时风扇是打开的timerCheck(time=60*15,func=switchFan,args=(fanState))print('now fanState :',fanState)order=''while order!='exit':order=input('input you order:')GPIO.cleanup()

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

时间校准及离家模式

白天我不在家,风扇得保证不开,那首先得保证树莓派的时间正确。设置下定时更新网络上的时间,时区也得保证是我所用的时区,上海时区。

# 安装ntpdate
apt-get install ntpdate
# 选择时区
sudo tzselect
# 然后选择亚洲 Asia->中国(China)->北京(Beijing)
# 接着复制到etc下
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# 更新时间,会得到正确时区的服务器时间
sudo ntpdate ntp.ubuntu.com
# 每天校准,添加到定时任务里面去
vi /etc/crontab
# 加入下面这个,每天6点十分校准
# 10 6 * * * root ntpdate ntp.ubuntu.com

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

然后我一般是7:30离家上班去,9:30左右回到家,所以在这个区间,如果我忘记关风扇了,它也应该保证不开,只要判断这个时间段就OK了:

# 判断当前是否离家了
def isLeave(leave=[7,30],back=[21,30]):now=time.localtime(time.time())return not (((now.tm_hour==leave[0] and now.tm_min>=leave[1]) ornow.tm_hour>leave[0]) and ((now.tm_hour==back[0] and now.tm_min1]) ornow.tm_hour0]))

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

编写服务器端接受指令

运行程序后,风扇就一直按照既定的模式运行,开一会关一会好像也不太好,比如今天天气比较热,我回来的比较早,我想它先扇两个小时,然后再开半个小时,关十五分钟,这样循环怎么办?嗯,还是得有个遥控器,反正树莓派联了家里的网,一回来手机也是要联上Wifi,那就直接用手机来做遥控器了。
想要手机控制树莓派,在树莓派上运行一个服务来接受来自手机的指令肯定是少不了的。一事不劳二主,依旧Python了。先写一个SmartServer的类,来创建服务器的Socket,来接受客服端的连接以及连接后的指令。

#-*- coding: utf-8 -*-
from socket import *
from time import ctime
from time import localtime
import threading
import time
import datetimeclass SmartServer(object):"""docstring for SmartServer"""HOST=''PORT=1122 #设置侦听端口BUFSIZ=1024 #buffer的大小SERVERFLAG=TruefanSwitchTimestamp=0 #风扇上次状态切换时候的时间fanState=0 #风扇当前状态fanForceClose=True #是否强制关闭风扇,离家的时候def __init__(self):super(SmartServer, self).__init__()def clientSocketDoWhat(self,client,address,clientId):while True:try:data=client.recv(self.BUFSIZ)except Exception as e:print('error when recv data from client!')breakif not data:break#python3使用bytes,所以要进行编码#s='%s发送给我的信息是:[%s] %s' %(addr[0],ctime(), data.decode('utf8'))#对日期进行一下格式化ISOTIMEFORMAT='%Y-%m-%d %X'stime=time.strftime(ISOTIMEFORMAT, localtime())s='getIt %d , %s' %(clientId,data.decode('utf8'))client.send(s.encode('utf8'))print([clientId],[stime], ':', data.decode('utf8'))#如果输入quit(忽略大小写),则程序退出quit=(data.decode('utf8').upper()=="QUIT")if quit:breakclient.close()def openServer(self,host='',port=1122,bufsize=1024):self.HOST=hostself.PORT=portself.BUFSIZ=bufsizeADDR=(self.HOST, self.PORT)sock=socket(AF_INET, SOCK_STREAM)sock.bind(ADDR)sock.listen(5)print('Server start')while self.SERVERFLAG:print('等待接入,侦听端口:%d' % (self.PORT))tcpClientSock, addr=sock.accept()print('接受连接,客户端地址:',addr)clientId=int(time.time());print('分派给客户端的ID:%d'%(clientId))th=threading.Thread(target=SmartServer.clientSocketDoWhat,args=(self,tcpClientSock,addr,clientId,))th.setDaemon(True)th.start()sock.close()# 测试代码
if __name__ == "__main__":server=SmartServer()serverThread=threading.Thread(target=server.openServer,args=())serverThread.setDaemon(True)serverThread.start()print('server thread start')serverThread.join()

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75

写好后要确保它能正常工作,所以再写个客服端client.py:

#-*- coding: utf-8 -*-
from socket import *class TcpClient:#测试,连接服务器HOST='192.168.1.102'#设置侦听端口PORT=1122 BUFSIZ=1024ADDR=(HOST, PORT)def __init__(self):self.client=socket(AF_INET, SOCK_STREAM)self.client.connect(self.ADDR)while True:data=input('>')if not data:break#python3传递的是bytes,所以要编码self.client.send(data.encode('utf8'))print('发送信息到%s:%s' %(self.HOST,data))if data.upper()=="QUIT":break data=self.client.recv(self.BUFSIZ)if not data:print('no info from server, exit!')breakprint('从%s收到信息:%s' %(self.HOST,data.decode('utf8')))if __name__ == '__main__':client=TcpClient()

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

在树莓派上运行服务器,然后在另外一台电脑上运行客服端,运行结果如下。这样树莓派就可以接受来自局域网的控制指令了。

Android端遥控器

树莓派的服务器端已经准备好了,并且测试通过了,那下一步就是来做个客户端。其实也看的出来,Android端的代码会比较简单,写个Socket连接上树莓派,发送指令基本就OK了。主要代码如下:

public class SmartClient implements Runnable{private UserConfig cOnfig=UserConfig.getInstance();private boolean socketFlag=false;private Gson gson;private String charSet="utf-8";private byte[] dataFromServer=new byte[2048];private Thread mThread;private Socket mSocket;private LinkedBlockingQueue commands;public SmartClient(){gson=new GsonBuilder().create();commands=new LinkedBlockingQueue<>();mThread=new Thread(this);}public void connectServer(){socketFlag=true;mThread.start();}private void connectToServer() throws IOException {Log.e("wuwang","try connect to socket"+config.getIp()+":"+config.getPort());mSocket=new Socket();mSocket.connect(new InetSocketAddress(config.getIp(),config.getPort()));Log.e("wuwang","try connect to socket");while (!mSocket.isClosed()&&socketFlag){OutputStream stream=mSocket.getOutputStream();try {Command command=commands.poll(20, TimeUnit.SECONDS);if(command==null) {stream.write("{}".getBytes(charSet));}else{stream.write(gson.toJson(command).getBytes(charSet));}} catch (InterruptedException e) {e.printStackTrace();continue;}InputStream in=mSocket.getInputStream();int result=in.read(dataFromServer);if(result>0){String value=new String(dataFromServer,0,result);Log.e("wuwang","dataFromServer::"+value);}}}public void addCommand(Command command){commands.offer(command);}public void addCommand(int type,int value){Command c=new Command();c.type=type;commands.offer(c);}@Overridepublic void run() {try {connectToServer();} catch (IOException e) {e.printStackTrace();}}public void close(){socketFlag=false;if(mSocket!=null){try {mSocket.close();} catch (IOException e) {e.printStackTrace();}}try {mThread.join();} catch (InterruptedException e) {e.printStackTrace();}}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88

用Json来通信,来方便后面的扩展,用type来表示命令的类型,先做简单的,type为1表示强制打开风扇,type为0表示强制关闭。当然,控制端发送给树莓派后,树莓派需要解析出来,然后根据控制命令执行才行。增加解析这个type的来执行的代码到clientSocketDoWhat中,self.fanControl为测试gpio时的switchFan方法:

def clientSocketDoWhat(self,client,address,clientId):while self.SERVERFLAG:try:data=client.recv(self.BUFSIZ)except Exception as e:print(&#39;error when recv data from client!&#39;)breakif not data:break#python3使用bytes,所以要进行编码#s=&#39;%s发送给我的信息是:[%s] %s&#39; %(addr[0],ctime(), data.decode(&#39;utf8&#39;))#对日期进行一下格式化ISOTIMEFORMAT=&#39;%Y-%m-%d %X&#39;stime=time.strftime(ISOTIMEFORMAT, localtime())s=&#39;getIt %d , %s&#39; %(clientId,data.decode(&#39;utf8&#39;))client.send(s.encode(&#39;utf8&#39;))print([clientId],[stime], &#39;:&#39;, data.decode(&#39;utf8&#39;))command=json.loads(data.decode(&#39;utf8&#39;))type=command.get(&#39;type&#39;,-1)if type==1 :if self.fanControl:self.fanControl([1])elif type==0:if self.fanControl:self.fanControl([0])#如果输入quit(忽略大小写),则程序退出quit=(data.decode(&#39;utf8&#39;).upper()=="QUIT")if quit:breakclient.close()

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

这样手机也可以遥控电扇开关了。至于其他的更为复杂的,用手机设置定时时间,也就大同小异了,发送json过去,树莓派解析,然后完成设置进行控制就OK了。

至此,风扇定时及android手机控制风扇的功能就OK了。



推荐阅读
  • Python 程序转换为 EXE 文件:详细解析 .py 脚本打包成独立可执行文件的方法与技巧
    在开发了几个简单的爬虫 Python 程序后,我决定将其封装成独立的可执行文件以便于分发和使用。为了实现这一目标,首先需要解决的是如何将 Python 脚本转换为 EXE 文件。在这个过程中,我选择了 Qt 作为 GUI 框架,因为之前对此并不熟悉,希望通过这个项目进一步学习和掌握 Qt 的基本用法。本文将详细介绍从 .py 脚本到 EXE 文件的整个过程,包括所需工具、具体步骤以及常见问题的解决方案。 ... [详细]
  • 本文详细解析了客户端与服务器之间的交互过程,重点介绍了Socket通信机制。IP地址由32位的4个8位二进制数组成,分为网络地址和主机地址两部分。通过使用 `ipconfig /all` 命令,用户可以查看详细的IP配置信息。此外,文章还介绍了如何使用 `ping` 命令测试网络连通性,例如 `ping 127.0.0.1` 可以检测本机网络是否正常。这些技术细节对于理解网络通信的基本原理具有重要意义。 ... [详细]
  • 属性类 `Properties` 是 `Hashtable` 类的子类,用于存储键值对形式的数据。该类在 Java 中广泛应用于配置文件的读取与写入,支持字符串类型的键和值。通过 `Properties` 类,开发者可以方便地进行配置信息的管理,确保应用程序的灵活性和可维护性。此外,`Properties` 类还提供了加载和保存属性文件的方法,使其在实际开发中具有较高的实用价值。 ... [详细]
  • Python 序列图分割与可视化编程入门教程
    本文介绍了如何使用 Python 进行序列图的快速分割与可视化。通过一个实际案例,详细展示了从需求分析到代码实现的全过程。具体包括如何读取序列图数据、应用分割算法以及利用可视化库生成直观的图表,帮助非编程背景的用户也能轻松上手。 ... [详细]
  • 为了确保iOS应用能够安全地访问网站数据,本文介绍了如何在Nginx服务器上轻松配置CertBot以实现SSL证书的自动化管理。通过这一过程,可以确保应用始终使用HTTPS协议,从而提升数据传输的安全性和可靠性。文章详细阐述了配置步骤和常见问题的解决方法,帮助读者快速上手并成功部署SSL证书。 ... [详细]
  • Python多线程编程技巧与实战应用详解 ... [详细]
  • 使用 ListView 浏览安卓系统中的回收站文件 ... [详细]
  • 在 CentOS 7 系统中安装 Scrapy 时遇到了一些挑战。尽管 Scrapy 在 Ubuntu 上安装简便,但在 CentOS 7 上需要额外的配置和步骤。本文总结了常见问题及其解决方案,帮助用户顺利安装并使用 Scrapy 进行网络爬虫开发。 ... [详细]
  • 在处理 XML 数据时,如果需要解析 `` 标签的内容,可以采用 Pull 解析方法。Pull 解析是一种高效的 XML 解析方式,适用于流式数据处理。具体实现中,可以通过 Java 的 `XmlPullParser` 或其他类似的库来逐步读取和解析 XML 文档中的 `` 元素。这样不仅能够提高解析效率,还能减少内存占用。本文将详细介绍如何使用 Pull 解析方法来提取 `` 标签的内容,并提供一个示例代码,帮助开发者快速解决问题。 ... [详细]
  • 本文探讨了如何利用Java代码获取当前本地操作系统中正在运行的进程列表及其详细信息。通过引入必要的包和类,开发者可以轻松地实现这一功能,为系统监控和管理提供有力支持。示例代码展示了具体实现方法,适用于需要了解系统进程状态的开发人员。 ... [详细]
  • 在开发过程中,我最初也依赖于功能全面但操作繁琐的集成开发环境(IDE),如Borland Delphi 和 Microsoft Visual Studio。然而,随着对高效开发的追求,我逐渐转向了更加轻量级和灵活的工具组合。通过 CLIfe,我构建了一个高度定制化的开发环境,不仅提高了代码编写效率,还简化了项目管理流程。这一配置结合了多种强大的命令行工具和插件,使我在日常开发中能够更加得心应手。 ... [详细]
  • Java Socket 关键参数详解与优化建议
    Java Socket 的 API 虽然被广泛使用,但其关键参数的用途却鲜为人知。本文详细解析了 Java Socket 中的重要参数,如 backlog 参数,它用于控制服务器等待连接请求的队列长度。此外,还探讨了其他参数如 SO_TIMEOUT、SO_REUSEADDR 等的配置方法及其对性能的影响,并提供了优化建议,帮助开发者提升网络通信的稳定性和效率。 ... [详细]
  • 深入剖析Java中SimpleDateFormat在多线程环境下的潜在风险与解决方案
    深入剖析Java中SimpleDateFormat在多线程环境下的潜在风险与解决方案 ... [详细]
  • 在Android平台中,播放音频的采样率通常固定为44.1kHz,而录音的采样率则固定为8kHz。为了确保音频设备的正常工作,底层驱动必须预先设定这些固定的采样率。当上层应用提供的采样率与这些预设值不匹配时,需要通过重采样(resample)技术来调整采样率,以保证音频数据的正确处理和传输。本文将详细探讨FFMpeg在音频处理中的基础理论及重采样技术的应用。 ... [详细]
  • 分享一款基于Java开发的经典贪吃蛇游戏实现
    本文介绍了一款使用Java语言开发的经典贪吃蛇游戏的实现。游戏主要由两个核心类组成:`GameFrame` 和 `GamePanel`。`GameFrame` 类负责设置游戏窗口的标题、关闭按钮以及是否允许调整窗口大小,并初始化数据模型以支持绘制操作。`GamePanel` 类则负责管理游戏中的蛇和苹果的逻辑与渲染,确保游戏的流畅运行和良好的用户体验。 ... [详细]
author-avatar
Tags | 热门标签
RankList | 热门文章
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有