想在flask编写的服务器程序实现这样一个功能,与底层硬件通信。底层硬件是网络接口,通过TCP/UDP协议进行数据传输。因此服务器需要使用socket。然而flask的socket是websocket,它虽然从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)#发给客户端
对于上图中的通信B很容易搞定,下面主要是解决通信A的问题。
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来发送数据
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
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无法开启,具体原因正在查明