在flask里加socket进行底层通信

问题

想在flask编写的服务器程序实现这样一个功能,与底层硬件通信。底层硬件是网络接口,通过TCP/UDP协议进行数据传输。因此服务器需要使用socket。然而flask的socket是websocket,它虽然从socket衍生出来,但仅用于与客服端进行数据交互。怎么办?

解决办法

  • socket加还是要加的。socket有两种用法,一种是在客户端的用法,一种是服务端的用法。如果硬件是服务端,需要flask的程序向服务端请求数据,这个直接加socket就行
@socketio.on('needdata')
def onNeeddata():
	sock=socket.socket(socket.AF_INET, socket.SOCK_STREAM)#建立一个socket
	sock.connect(hardware_addr)#连接到硬件
	sock.send(cmd)#向硬件发送指令
	data=sock.recv(1024)#接收硬件的数据
	socketio.emit("givedata",data)#发给客户端
  • 然而如果硬件是客户端,又如何呢? 这样socket的程序就相当于开了两个服务器,一个连接客户端,一个是连接硬件
客户端
服务端
硬件
通信A
通信B
WEB客户端口
flaskWEB服务端口
socket服务端口
socket客户端口

对于上图中的通信B很容易搞定,下面主要是解决通信A的问题。

  1. 基本的socket服务端程序
sock=socket.socket(socket.AF_INET, socket.SOCK_STREAM)#新建socket
sock.bind(address)#绑定地址
sock.listen(30)
connection, addr=sock.accept()#等待客户端发送消息,此时程序阻塞在这,如果收到消息会往下执行。
msg=connection.recv(1024)#通过新生成的connection来接收消息,connection也是一个socket
connection.sendto(data,client_address)#通过新生成的connection来发送数据
  1. 可处理多个连接的socket服务端程序
    基本的用法只能一次接收一个客户端的连接,并且也程序也有阻塞,若没收到消息,则程序一直原地踏步。要处理多个连接,可以设置一个主循环,来不断的接收消息,还不断的发送数据,并且同时处理多个连接。
sock=socket.socket(socket.AF_INET, socket.SOCK_STREAM)#新建socket
sock.setblocking(False)#设置成非阻塞
sock.bind(address)#绑定地址
sock.listen(30)
CLIENT=[]#客户的列表
while True:
    if stop():#退出循环
        break
    try:
        connection, addr=sock.accept()
        CLIENT.append((connection,addr))
    except BlockingIOError:#有阻塞异常,可以pass掉
        pass
    for c_socket,c_addr in client_list:
        try:
            msg=c_socket.recv(1024)#接收数据
        except (BlockingIOError, ConnectionResetError):
            pass
        c_socket.sendto(data,c_addr )#发送数据
#清理连接到客户端的socket
for c_socket,c_addr in client_list:
    c_socket.close()
    client_list.remove((c_socket,c_addr))
sock.close()#关闭服务器的socket
  1. socket加线程
    flask框架其实也有一个大循环,两个大循环要合并的话,就需要通过线程来实现。将通信A的socket放到线程里,可以将socket的连接客户端的程序做一个线程,接收数据又是一个线程。
sock=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setblocking(False)#设置成非阻塞
CLIENT=[]
app=Flask(__name__)
#连接线程
def connect():
    while True:
        if stop():
            break
        try:
            connection, addr=sock.accept()
            CLIENT.append((connection, addr))
            print("接收到新模块 其地址为:",addr,"目前模块有",len(CLIENT),"个")
        except BlockingIOError:
            pass
def receive():
    while True:
        if stop():
            break
        for c_socket,c_addr in CLIENT:
            try:
                msg=c_socket.recv(1024)
            except (BlockingIOError, ConnectionResetError):
                pass
@app.route('/')
def index():
    sock.bind(server_address)
    sock.listen(30)
    heartbeat()
    connect_run=threading.Thread(target=connect)#连接客户端线程
    receive_run=threading.Thread(target=receive)#接收数据线程
    connect_run.start()#启动连接客户端线程
    receive_run.start()#启动接收数据线程
    return render_template('index.html')
#开启flask服务器
if __name__=="__main__":
    socketio.run(app, debug=True, host=SERVER_IP, port=SERVER_PORT)
    for c_socket,c_addr in CLIENT:
        c_socket.close()
        CLIENT.remove((c_socket,c_addr))
    sock.close()

需要注意的是socket的bind函数和listen函数必须在flask里面的某个路径函数里,如果放在开启flask前面就开启线程,则flask无法开启,具体原因正在查明

你可能感兴趣的:(python#flask,python,flask,socket)