专栏名称: Python学习交流
每天更新,更新python相关的知识。希望诸君有所收获!
目录
相关文章推荐
Python爱好者社区  ·  史上最强!PINN杀疯了 ·  昨天  
Python爱好者社区  ·  DeepSeek创始人梁文锋个人履历 ·  3 天前  
Python爱好者社区  ·  离谱!下载DeepSeek最高判刑20年? ·  2 天前  
Python爱好者社区  ·  1885页的Python完全版电子书 ·  3 天前  
Python开发者  ·  o3-mini 碾压 DeepSeek ... ·  5 天前  
51好读  ›  专栏  ›  Python学习交流

python 实现微信远程控制唤醒内网机器和远程关闭windows 主机

Python学习交流  · 公众号  · Python  · 2018-12-28 16:08

正文

有时候需要远程开下家里的台式机使用,因为我平时都是用 mac 多,但是远程唤醒只能针对局域网,所以比较麻烦。于是我想着用微信实现远程唤醒机器,正好手上有个闲置的树莓派,想着可以利用起来。

租的房子,电费1块2一度,索性把台式机扛回家,家里电费便宜,以后要用 Windows(主要是开虚拟机),就远程吧。

准备工作

本程序,主要是实现远程管理 Windows10操作系统的开机和关机:

1.在 Windows机器的相同内网中放一个 linux 主机,我这里用树莓派代替,如果你是用 openwrt 之类的路由器也可以。

2.linux 主机需要能够远程访问,我这里是有 frp 将树莓派的端口映射到我的公网 linux 主机上。所以可以随时远程 ssh 过去。

3.Windows 机器的网卡必须是有线连接,支持网络唤醒功能。

开机实现思路

首先通过微信发送开机指令,这里我使用的是 itchat 程序会调用 paramiko 库去ssh 远程到内网的树莓派执行 wakeonlan 命令去唤醒 Windows 主机。

pi@raspberrypi:~ $ wakeonlan  -i 192.168.1.0 14:dd:a9:ea:0b:96Sending magic packet to 192.168.1.0:9 with 14:dd:a9:ea:0b:96

接下来,程序会通过 icmp 协议,也就是 ping 下需要唤醒的目标主机然后过滤下,一个正常的 icmp 包是64字节,过滤打印出这个64

例如 ping 百度

➜  ~ ping www.baidu.comPING www.a.shifen.com (180.97.33.108): 56 data bytes64 bytes from 180.97.33.108: icmp_seq=0 ttl=53 time=8.865 ms64 bytes from 180.97.33.108: icmp_seq=1 ttl=53 time=9.206 ms64 bytes from 180.97.33.108: icmp_seq=2 ttl=53 time=8.246 ms

我这里用一段 linux 命令去过滤是否有64,这里为啥要用 head -n 1 呢,因为有可能会出现2行,经过测试,我们只需要取64这个值就可以了

ping 192.168.1.182 -c 1 | grep 64 | cut -d " " -f 1|head -n 1

如果有则表示开机成功已经联网了,返回开机成功,否则程序继续往下走,去唤醒,然后在 ping 一次确认是否开机,如果为是则返回开机成功,否则返回失败。程序执行成功后,在我的网站根目录创建一个 shutdown 文件,用于后面的关机操作

#!/usr/bin/python# -*- coding: utf-8 -*-import itchatimport paramikoimport osimport timeimport sys
reload(sys)
sys.setdefaultencoding('utf-8')

hostname = ''username = ''port = 
key_file = '/home/fangwenjun/.ssh/id_rsa'filename = '/home/fangwenjun/.ssh/known_hosts'@itchat.msg_register(itchat.content.TEXT)def text_reply(msg):
    if msg['ToUserName'] != 'filehelper': return
    if msg['Text'] ==  u'开机':
        paramiko.util.log_to_file('ssh_key-login.log')
        privatekey = os.path.expanduser(key_file) 
        try:
            key = paramiko.RSAKey.from_private_key_file(privatekey)        except paramiko.PasswordRequiredException:
            key = paramiko.RSAKey.from_private_key_file(privatekey,key_file_pwd)

        ssh = paramiko.SSHClient()
        ssh.load_system_host_keys(filename=filename)
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh.connect(hostname=hostname,username=username,pkey=key,port=port)        #执行唤醒命令
        stdin,stdout,stderr=ssh.exec_command('ping 192.168.1.182 -c 1 | grep 64 | cut -d " " -f 1|head -n 1')
        sshCheckOpen = stdout.read()
        sshCheckOpen =sshCheckOpen.strip('\n')        print type(sshCheckOpen)        print sshCheckOpen        #进行判断,如果为64,则说明 ping 成功,说明设备已经在开机状态,程序结束,否则执行唤醒
        if sshCheckOpen == '64':
            connect_ok_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) 
            itchat.send(connect_ok_time+u'设备已经开机', toUserName='filehelper')        else:
            ssh_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) 
            itchat.send(ssh_time+u'开始连接远程主机', toUserName='filehelper')
            stdin,stdout,stderr=ssh.exec_command('wakeonlan -i 192.168.1.0 14:dd:a9:ea:0b:96')
            wakeonlan_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) 
            itchat.send(wakeonlan_time+u'执行唤醒,等待设备开机联网', toUserName='filehelper')            #由于开机需要一些时间去启动网络,所以这里等等60s    
            time.sleep(60)            #执行 ping 命令,-c 1 表示只 ping 一下,然后过滤有没有64,如果有则获取64传给sshConStatus
            stdin,stdout,stderr=ssh.exec_command('ping 192.168.1.182 -c 1 | grep 64 | cut -d " " -f 1|head -n 1')
            sshConStatus = stdout.read()
            sshConStatus =sshConStatus.strip('\n')            print type(sshConStatus)            print sshConStatus            #进行判断,如果为64,则说明 ping 成功,设备已经联网,可以进行远程连接了,否则发送失败消息
            if sshConStatus == '64':
                connect_ok_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) 
                itchat.send(connect_ok_time+u'设备唤醒成功,您可以远程连接了', toUserName='filehelper')            else:
                connect_err_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                itchat.send(connect_err_time+u'设备唤醒失败,请检查设备是否连接电源', toUserName='filehelper')
            ssh.close()            #在网站根目录创建一个空文件,命名为 shutdown
            os.system('touch /www/shutdown')            print '执行开机消息成功'

关机部分实现

当接收关机指令时,程序会去删除网站根目录的 shutdown 文件,客户端我写了几行代码,去通过 requests 库每隔30s 发送 http head 请求去判断文件是否是404,如果是404 这说明文件不存在,调用系统关机操作,执行关机,然后还是 ssh 到树莓派去 ping 目标主机,如果返回为空,则说明关机成功,否则关机失败。这只是针对 Windows 的关机,如果目标主机是 linux 则简单多了。

if msg['Text'] ==  u'关机':        #删除网站根目录的shutdown 文件
        rmfile = os.system('rm -rf /www/shutdown')        if rmfile == 0:            print '执行关机消息成功'
        shutdown_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) 
        itchat.send(shutdown_time+u'正在关机....', toUserName='filehelper')
        paramiko.util.log_to_file('ssh_key-login.log'






请到「今天看啥」查看全文


推荐文章
Python爱好者社区  ·  史上最强!PINN杀疯了
昨天
Python爱好者社区  ·  DeepSeek创始人梁文锋个人履历
3 天前
Python爱好者社区  ·  离谱!下载DeepSeek最高判刑20年?
2 天前
Python爱好者社区  ·  1885页的Python完全版电子书
3 天前
科学网  ·  返校集中写论文
7 年前
天籁之音  ·  光与爱:天使奏鸣曲(2)
7 年前