Ubuntu 17.10
上比较好用的串口终端是minicom
,下面我们介绍一下使用方法。
OpenMediaVault-4.0.15执行更新(apt update)时报错“TypeError: 'NoneType' object is not callable”
OpenMediaVault-4.0.15
执行更新(apt update
)时报错,详细错误信息如下:
1 2 3 4 5 6 7 8 9 10 |
命中:12 http://packages.openmediavault.org/public arrakis InRelease Exception ignored in: <function WeakValueDictionary.__init__.<locals>.remove at 0x7f7dc337b730> Traceback (most recent call last): File "/usr/lib/python3.5/weakref.py", line 117, in remove TypeError: 'NoneType' object is not callable Exception ignored in: <function WeakValueDictionary.__init__.<locals>.remove at 0x7f7dc337b730> Traceback (most recent call last): File "/usr/lib/python3.5/weakref.py", line 117, in remove TypeError: 'NoneType' object is not callable |
通过观察发现,只要从packages.openmediavault.org
中下载文件失败,就会报告这个错误。
发生错误之后,重新执行
1 |
$ sudo apt update |
即可解决这个问题,或者忽略这个错误信息即可。
Python中用Ctrl+C终止threading初始化的多线程脚本
在编写Python
脚本的时候,难免会遇到使用多线程操作的情况。
正常情况下,我们都习惯在Shell
中使用Ctrl+C
终止脚本的执行,但是在多线程环境中,我们发现Ctrl+C
并不能有效终止开启了多线程的脚本。
由于Python
提供的threading
模块并没有提供线程的退出接口,导致我们没有办法终止已经正常运行的线程,尤其是线程被阻塞在内核的情况下。
解决这个问题的办法就是在线程初始化之后设置为守护模式(setDaemon
),并且不要调用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 |
#!/bin/env python # -*- coding: utf-8 -*- import threading import signal import sys import time global is_exit is_exit = False def doWork(i): print "thread[%d] enter\n"%(i) while not is_exit: time.sleep(0.2) print "thread[%d] terminated\n"%(i) def sig_handler(signum, frame): is_exit = True sys.exit(0) if __name__ == "__main__": signal.signal(signal.SIGINT, sig_handler) signal.signal(signal.SIGTERM, sig_handler) cc = 5 for i in range(cc): t = threading.Thread(target=doWork, args=(i,)) t.setDaemon(True) t.start() raw_input("Waiting For Ctrl+C\n") |
参考链接
ubuntu 14.04/ubuntu 17.10做主机双网卡共享上网(NAT)
需求是电脑通过无线上网,然后把有线共享给其他设备,其他设备通过电脑代理上网。
电脑上有两张网卡,一张有线网卡,名字为eth0
,一张无线网卡,名字为wlan0
。
电脑的有线网卡配置的静态IP
地址为:192.168.0.1
。
对于Ubuntu 16.10/17.10
系统,请参考 Ubuntu 16.10/17.10无法通过/etc/rc.local开机启动应用 激活系统对于/etc/rc.local
功能的支持。
电脑上执行如下命令:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
$ echo "1" | sudo tee /proc/sys/net/ipv4/ip_forward $ sudo iptables -F $ sudo iptables -P INPUT ACCEPT $ sudo iptables -P FORWARD ACCEPT #打开NAT,无线网卡这里大eth0改wlan0 $ sudo iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE #保存设置信息,下次开机自动开启代理 $ sudo sed -i '$a\net.ipv4.ip_forward = 1' /etc/sysctl.conf $ sudo sed -i '$a\iptables -F' /etc/rc.local $ sudo sed -i '$a\iptables -P INPUT ACCEPT' /etc/rc.local $ sudo sed -i '$a\iptables -P FORWARD ACCEPT' /etc/rc.local $ sudo sed -i '$a\iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE' /etc/rc.local |
此时,由于我们没有开启DHCP
功能,因此只能设置静态IP
地址。客户机设置如下:
eth0:192.168.0.10
掩码:255.255.255.0
网关:192.168.0.1
参考链接
Python简单实现WebSocket
实现一个简单的聊天室程序,代码如下:
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 89 90 91 92 93 94 95 96 |
#-*- coding:utf8 -*- import threading import hashlib import socket import base64 global clients clients = {} #通知客户端 def notify(message): for connection in clients.values(): connection.send('%c%c%s' % (0x81, len(message), message)) #客户端处理线程 class websocket_thread(threading.Thread): def __init__(self, connection, username): super(websocket_thread, self).__init__() self.connection = connection self.username = username def run(self): print 'new websocket client joined!' data = self.connection.recv(1024) headers = self.parse_headers(data) token = self.generate_token(headers['Sec-WebSocket-Key']) self.connection.send('\ HTTP/1.1 101 WebSocket Protocol Hybi-10\r\n\ Upgrade: WebSocket\r\n\ Connection: Upgrade\r\n\ Sec-WebSocket-Accept: %s\r\n\r\n' % token) while True: try: data = self.connection.recv(1024) except socket.error, e: print "unexpected error: ", e clients.pop(self.username) break data = self.parse_data(data) if len(data) == 0: continue message = self.username + ": " + data notify(message) def parse_data(self, msg): v = ord(msg[1]) & 0x7f if v == 0x7e: p = 4 elif v == 0x7f: p = 10 else: p = 2 mask = msg[p:p+4] data = msg[p+4:] return ''.join([chr(ord(v) ^ ord(mask[k%4])) for k, v in enumerate(data)]) def parse_headers(self, msg): headers = {} header, data = msg.split('\r\n\r\n', 1) for line in header.split('\r\n')[1:]: key, value = line.split(': ', 1) headers[key] = value headers['data'] = data return headers def generate_token(self, msg): key = msg + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11' ser_key = hashlib.sha1(key).digest() return base64.b64encode(ser_key) #服务端 class websocket_server(threading.Thread): def __init__(self, port): super(websocket_server, self).__init__() self.port = port def run(self): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.bind(('127.0.0.1', self.port)) sock.listen(5) print 'websocket server started!' while True: connection, address = sock.accept() try: username = "ID" + str(address[1]) thread = websocket_thread(connection, username) thread.start() clients[username] = connection except socket.timeout: print 'websocket connection timeout!' if __name__ == '__main__': server = websocket_server(9000) server.start() |
测试页面:
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 89 90 91 92 93 94 95 |
<!-- @http://www.cnblogs.com/zhuweisky/p/3930780.html --> <!DOCTYPE html> </html> <head> <meta charset="utf-8"> </head> <body> <h3>WebSocketTest</h3> <div id="login"> <div> <input id="serverIP" type="text" placeholder="服务器IP" value="127.0.0.1" autofocus="autofocus" /> <input id="serverPort" type="text" placeholder="服务器端口" value="9000" /> <input id="btnConnect" type="button" value="连接" onclick="connect()" /> </div> <div> <input id="sendText" type="text" placeholder="发送文本" value="I'm WebSocket Client!" /> <input id="btnSend" type="button" value="发送" onclick="send()" /> </div> <div> <div> 来自服务端的消息 </div> <textarea id="txtContent" cols="50" rows="10" readonly="readonly"></textarea> </div> </div> </body> <script> var socket; function connect() { var host = "ws://" + $("serverIP").value + ":" + $("serverPort").value + "/" socket = new WebSocket(host); try { socket.onopen = function (msg) { $("btnConnect").disabled = true; alert("连接成功!"); }; socket.onmessage = function (msg) { if (typeof msg.data == "string") { displayContent(msg.data); } else { alert("非文本消息"); } }; socket.onclose = function (msg) { alert("socket closed!") }; } catch (ex) { log(ex); } } function send() { var msg = $("sendText").value socket.send(msg); } window.onbeforeunload = function () { try { socket.close(); socket = null; } catch (ex) { } }; function $(id) { return document.getElementById(id); } Date.prototype.Format = function (fmt) { //author: meizz var o = { "M+": this.getMonth() + 1, //月份 "d+": this.getDate(), //日 "h+": this.getHours(), //小时 "m+": this.getMinutes(), //分 "s+": this.getSeconds(), //秒 "q+": Math.floor((this.getMonth() + 3) / 3), //季度 "S": this.getMilliseconds() //毫秒 }; if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)); for (var k in o) if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); return fmt; } function displayContent(msg) { $("txtContent").value += "\r\n" +new Date().Format("yyyy/MM/dd hh:mm:ss")+ ": " + msg; } function onkey(event) { if (event.keyCode == 13) { send(); } } </script> </html> |
参考链接
原生JS写Ajax的请求函数
一般我们写网页的时候,如果用到Ajax
请求服务器,都是使用JQuery
等已经封装好的库来调用,比较简单。
但是一般这些库的功能很多,引入了太多我们用不到的东西,如果我们需要写一个功能单一,简单的页面,完全用不到引用如此庞大的库文件。
我们可以简单实现一个自己的Ajax
请求功能,具体的代码如下:
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 |
var ajax = {}; ajax.x = function () { if (typeof XMLHttpRequest !== 'undefined') { return new XMLHttpRequest(); } var versions = [ "MSXML2.XmlHttp.6.0", "MSXML2.XmlHttp.5.0", "MSXML2.XmlHttp.4.0", "MSXML2.XmlHttp.3.0", "MSXML2.XmlHttp.2.0", "Microsoft.XmlHttp" ]; var xhr; for (var i = 0; i < versions.length; i++) { try { xhr = new ActiveXObject(versions[i]); break; } catch (e) { } } return xhr; }; ajax.send = function (url, method, data, success,fail,async) { if (async === undefined) { async = true; } var x = ajax.x(); x.open(method, url, async); x.onreadystatechange = function () { if (x.readyState == 4) { var status = x.status; if (status >= 200 && status < 300) { success && success(x.responseText,x.responseXML) } else { fail && fail(status); } } }; if (method == 'POST') { x.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); } x.send(data) }; ajax.get = function (url, data, callback, fail, async) { var query = []; for (var key in data) { query.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key])); } ajax.send(url + (query.length ? '?' + query.join('&') : ''), 'GET', null, callback, fail, async) }; ajax.post = function (url, data, callback, fail, async) { var query = []; for (var key in data) { query.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key])); } ajax.send(url,'POST', query.join('&'), callback, fail, async) }; |
使用方法:GET
1 2 3 4 5 6 |
ajax.get('/test.php', {foo: 'bar'}, function(response,xml) { //success }, function(status){ //fail }); |
POST
1 2 3 4 5 6 7 |
ajax.post('/test.php', {foo: 'bar'}, function(response,xml) { //succcess },function(status){ //fail }); |
这里需要注意一个问题,如果我们想要发送类似
1 |
http://www.mobibrw.com/control?op_code=code&op_cmd=cmd |
的URL
,是不能通过上面的发送方式(字段填写在data
参数中)发送的,上面的发送方式是属于表单的上传方式。
我们需要用下面的方式进行处理(自己拼凑URL
)
1 2 3 4 5 6 7 |
var sendCmd = "?op_code=" + code + "&op_cmd=" + cmd; ajax.post('/control' + sendCmd,'',function(response,xml) { console.log('success'); }, function(status){ console.log('failed:' + status); }); |
参考链接
树莓派2 B+任务栏(LXPanel)不断闪烁消失(RASPBIAN STRETCH WITH DESKTOP)
长时间不用的一个树莓派2 B+
,使用的系统为RASPBIAN STRETCH WITH DESKTOP
。在重新加电后,任务栏(LXPanel
)不断闪烁消失,貌似启动的时候发生了异常,然后崩溃,重启,循环往复(并不是一直消失不见,而是不断闪烁)。但是查看系统日志,却找不到相关的异常日志。
这种现象,可以通过如下方法解决:
1 2 3 4 5 6 7 8 9 |
$ sudo apt-get remove --purge lxpanel $ sudo apt-get install lxpanel $ sudo apt-get autoremove $ rm -rf ~/.config/lxpanel/LXDE-pi $ sudo reboot |
参考链接
树莓派3 B+下次启动强制检查系统分区
树莓派使用的过程中,难免会由于突然断电等原因导致SD
卡发生错误。这个时候我们就需要强制让树莓派在下次启动的时候进行磁盘检查。
如果是普通分区,可以卸载后执行fsck
命令,但是如果是系统分区,由于一直被占用,因此是没有办法进行磁盘检查的。
网上找了一下,找到了解决办法,可以强制让树莓派在下次系统启动的时候,强制检查系统分区。具体的方式如下:
1 2 3 |
$ sudo touch /forcefsck $ sudo reboot |
参考链接
树莓派3 B+设置静态IP
最近需要为一台树莓派3 B+
设置静态IP
地址,结果尝试了半天总是不成功。
网上搜索了一下,找到解决方法。
修改/etc/dhcpcd.conf
文件
1 |
$ sudo vim /etc/dhcpcd.conf |
在文件的尾部增加如下内容:
1 2 3 4 5 6 7 8 9 10 11 |
interface eth0 static ip_address=192.168.0.10/24 static routers=192.168.0.1 static domain_name_servers=192.168.0.1 interface wlan0 static ip_address=192.168.0.200/24 static routers=192.168.0.1 static domain_name_servers=192.168.0.1 |
上面的配置文件中,eth0
是有线的配置, wlan0
是无线配置
ip_address
就是静态IP
, 后面要接/24
routers
是网关
domain_name_servers
是DNS
参考链接
树莓派3 UART及GPIO针脚定义
树莓派GPIO接口只能输入输出数字信号(0&1等),传感器等模拟信号,需要通过ADC(模数转换器)进行转化。
树莓派3的GPIO管脚定义与前代有所差别了,具体的管脚参照下图: