【编程实践/嵌入式比赛】嵌入式比赛学习记录(一):TCP服务器和web界面的建立

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

具体的处理过程是:

  1. 调用self.requests.recv,接收数据,参数为接收长度
  2. 对数据进行处理,可以调用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发送数据,可以看到在前端已正常显示,证明实验成功。

【编程实践/嵌入式比赛】嵌入式比赛学习记录(一):TCP服务器和web界面的建立
【编程实践/嵌入式比赛】嵌入式比赛学习记录(一):TCP服务器和web界面的建立

; 7. 可改进的地方

  1. 可不可以直接向web server发送数据?我不好说,因为感觉还是要建立TCP连接才行
  2. 有没有其他转交方式?可以线程间共享变量,使用信号量控制发送接收关系,但可能很麻烦
  3. 前端更新数据除了ajax轮询还有没有更好的方式?可不可以实现真正的异步通讯,以免不必要的负载?

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

Original: https://blog.csdn.net/m0_51274130/article/details/124203782
Author: PlusE Lin
Title: 【编程实践/嵌入式比赛】嵌入式比赛学习记录(一):TCP服务器和web界面的建立

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/745707/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球