0. 前言
最近找同学参加了嵌入式比赛,为了让自己的简历不显得一穷二白,可惜我本人是计算机专业的学生,因此大部分的工作是上位机开发,可能也会搞一下WIFI模块。
由于在此过程中还是学到了一些东西,因此我打算以博客的形式记录之,以便后续浏览,也希望大家可以从我的博客中有所收获。
本人争取按时更新。
1. 本次任务介绍
目前接到的需求是上位机使用Web界面(最早的设想是GUI),将下位机传来的数据接收(使用TCP传输,后续可能改为UDP),并做处理后放到web网页上。因此我需要的工作是:
1.TCP server的建立(上位机做服务器,下位机做客户端)
2. Web界面的实现
3. TCP server向web server发送数据。
考虑到本人贫瘠的编程能力和web开发的需求,因此我打算使用Python开发。
TCP server使用socket库实现,web界面使用flask实现,通信则用requests由TCP server向web server的指定URL发送POST请求实现。
以下我将会介绍具体内容
2. TCP server的建立
Python中,可以使用socket库构建TCP server。
本人使用的是socketserver模块,其实也是基于socket的,使用这个模块的好处是可以更加方便的建立TCP server,甚至省去了创建时的绑定IP端口,调用accept阻塞的方法。
调用时的方法如下:
def start_TCP(host,port):
myserver=socketserver.ThreadingTCPServer((host,port),MyHandler)
print("You have start server,address is: {}:{}".format(host,port))
myserver.serve_forever()
我们注意到,在构造类ThreadingTCPServer时的第二个参数是MyHandler,这个是自定义的类,继承了socketserver.BaseRequestHandler类,需要重写handle函数,具体如下:
class MyHandler(socketserver.BaseRequestHandler):
def handle(self):
while True:
data=self.request.recv(1024)
try:
data=data.decode("gbk")
except:
data="cannot show normally!"
object={"data":time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())+" "+data}
if not data:
break
else:
print("Got: {}".format(data))
self.request.send("You have successfully sent data!".encode("ascii"))
with requests.post("http://192.168.71.1:5000/",json=object) as r:
pass
具体的处理过程是:
- 调用self.requests.recv,接收数据,参数为接收长度
- 对数据进行处理,可以调用self.request.send向客户端回送消息
至于向web server转发的内容,后文会介绍。
3. Flask web的建立
flask是一个开源web框架,学起来非常简单,只要有一定的web基础(甚至是常识)就能学会。
具体的代码如下:
from flask import *
import threading
app=Flask(__name__)
messages=[]
length=0
@app.route("/",methods=["GET","POST"])
def index_page():
global messages
data=request.get_json()
if data is not None:
messages.append(data["data"])
return render_template("index0.html",messages=messages)
@app.route("/get_data",methods=['GET','POST'])
def get_data():
global length
if(length<len(messages)):
length=len(messages)
return "flash"
return ""
其中前端代码如下
首先是index0.html,因为是学习部分,就放了几个数据
<html>
<head>
head>
<body>
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js">script>
<script type="text/javascript" src="{{url_for('static', filename = 'js/update.js')}}">script>
<h2>历史信息h2>
{% for each in messages %}
<p>{{each}}p>
{% endfor %}
body>
html>
这是比较简单的flask模板的编写,这里不再进行叙述。
然后是用到的JavaScript代码。很抱歉,本人对js并不熟悉,这些代码也是从网上找+自己改的,因此不能给出具体的解释。
var script=document.createElement("script");
script.type="text/javascript";
script.src="jquery.js";
setInterval(
function(){
$.ajax({
url:"/get_data",
async:true,
type:'post',
timeout:10000,
success:function(data){
if(data=="flash"){
window.location.reload();
}
},
error:function(xhr,type){
window.alert("error!");
}
})
},100
)
4. TCP server 向web server通信
这里就用到了一行,即requests.post请求
并且前面也已经展示了
with requests.post("http://192.168.71.1:5000/",json=object) as r:
pass
5. 总程序
总程序用来启动web server和TCP server,由于两个server都是持久服务,因此在主进程中启动一个就会陷入死循环,不能启动另一个,因此我将这两个服务器启动放到了两个线程上,并且设置了不同的端口号防止冲突。
(其实这里我一直陷入困惑,因为按照我浅显的计网知识,我觉得两个server应该在两个进程上,可放到两个线程上貌似也可以,反而是多进程失败了……后续有时间会探求一下)
from flask import *
import threading
import socketserver
import time
from app_views import *
from lib.MyServer import *
def start_TCP(host,port):
myserver=socketserver.ThreadingTCPServer((host,port),MyHandler)
print("You have start server,address is: {}:{}".format(host,port))
myserver.serve_forever()
def start_flask(host,port):
print("you have start flask server,address is: {}:{}".format(host,port))
app.run(host=host,port=port)
def main():
th1=threading.Thread(target=start_flask,args=("192.168.71.1",5000))
th2=threading.Thread(target=start_TCP,args=("192.168.71.1",5001))
th1.start()
th2.start()
if __name__=="__main__":
main()
6.验收
启动上述代码,打开网络调试助手,向192,168.71.1:5001发送数据,可以看到在前端已正常显示,证明实验成功。
; 7. 可改进的地方
- 可不可以直接向web server发送数据?我不好说,因为感觉还是要建立TCP连接才行
- 有没有其他转交方式?可以线程间共享变量,使用信号量控制发送接收关系,但可能很麻烦
- 前端更新数据除了ajax轮询还有没有更好的方式?可不可以实现真正的异步通讯,以免不必要的负载?
本篇文章到此,感谢收看!
Original: https://blog.csdn.net/m0_51274130/article/details/124203782
Author: PlusE Lin
Title: 【编程实践/嵌入式比赛】嵌入式比赛学习记录(一):TCP服务器和web界面的建立
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/745707/
转载文章受原作者版权保护。转载请注明原作者出处!