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阻塞的方法。

调用时的方法如下:

# 建立TCP server

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}

#没有接收到数据,不向web server转发

if not data:

break

else:

#本来打算做成线程间通信的,后来一想是web server,直接发post请求好了

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

#接收TCP server发送的数据

data=request.get_json()

#若有数据,则相应操作,这里是加入到全局列表中

if data is not None:

messages.append(data["data"])

#渲染模板

return render_template("index0.html",messages=messages)

#ajax会向此路由发送post请求轮询,用于异步更新路由

@app.route("/get_data",methods=['GET','POST'])

def get_data():

#发现有新数据加入的时候,要求前端进行相应动作,例如更新路由

global length

if(length

length=len(messages)

return "flash"

return ""

其中前端代码如下 首先是index0.html,因为是学习部分,就放了几个数据

历史信息

{% for each in messages %}

{{each}}


{% endfor %}

这是比较简单的flask模板的编写,这里不再进行叙述。 然后是用到的JavaScript代码。很抱歉,本人对js并不熟悉,这些代码也是从网上找+自己改的,因此不能给出具体的解释。

var script=document.createElement("script");

script.type="text/javascript";

script.src="jquery.js";

//ajax轮询,每100ms调用一次函数,即ajax请求

setInterval(

function(){

$.ajax({

url:"/get_data",

async:true,

type:'post', //貌似post才行,我很疑惑

timeout:10000,

success:function(data){

if(data=="flash"){

//your operation

window.location.reload();//刷新路由,也可以是其他操作

}

},

error:function(xhr,type){

window.alert("error!");

}

})

},100

)

4. TCP server 向web server通信

这里就用到了一行,即requests.post请求 并且前面也已经展示了

# 本实验中,web server的ip和端口为192.168.71.1:5000

with requests.post("http://192.168.71.1:5000/",json=object) as r:

pass

5. 总程序

总程序用来启动web server和TCP server,由于两个server都是持久服务,因此在主进程中启动一个就会陷入死循环,不能启动另一个,因此我将这两个服务器启动放到了两个线程上,并且设置了不同的端口号防止冲突。 (其实这里我一直陷入困惑,因为按照我浅显的计网知识,我觉得两个server应该在两个进程上,可放到两个线程上貌似也可以,反而是多进程失败了……后续有时间会探求一下)

### index.py

from flask import *

import threading

import socketserver

import time

# web服务器部分

from app_views import *

#TCP服务器部分

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轮询还有没有更好的方式?可不可以实现真正的异步通讯,以免不必要的负载?

本篇文章到此,感谢收看!

推荐链接

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。