英文:
Why is my flask server socketio connect event being called each time a message is emitted?
问题
我目前有一个React组件,它将连接到一个Web套接字并逐行打印接收到的数据。在服务器端,我的Flask应用程序将启动一个后台线程,每3秒发送一条测试消息。
每次服务器发出消息时,似乎都会调用connect()事件。这是预期的吗?还是与React组件有关?
React组件
const OutputWindow: React.FC = () => {
const socket = io('http://localhost:5000');
const [socketData, setSocketData] = useState<string[]>([]);
useEffect(() => {
socket.on('connect', () => {
console.log('Connect established');
})
socket.on('server_data', (data) => {
console.log('Received data from server! ' + data);
setSocketData(prevSocketData => [...prevSocketData, data]);
})
}, []);
return (
<div className="window">
{socketData.map((line, index) => (
<p className="log-line" key={index}>
{line}
</p>
))}
</div>
);
};
Flask服务器每3秒发送一条测试消息的代码:
log_thread = None
thread_lock = threading.Lock()
@socketio.on('connect')
def handle_connect():
print('Client connected')
# 启动线程以发送日志文件数据
global log_thread
with thread_lock:
if log_thread is None:
log_thread = socketio.start_background_task(send_data)
@socketio.on('disconnect')
def handle_disconnect():
print('A client disconnected')
def send_data():
print("Streaming thread started.")
while True:
socketio.emit("server_data", "test message")
socketio.sleep(3)
服务器端日志:
Client connected
192.168.0.163 - - [08/Aug/2023 15:11:44] "POST /socket.io/?EIO=4&transport=polling&t=OdLj3O8&sid=IQl7g7aZKld0tgYmAABc HTTP/1.1" 200 223 0.002163
192.168.0.163 - - [08/Aug/2023 15:11:44] "GET /socket.io/?EIO=4&transport=polling&t=OdLj3O9&sid=IQl7g7aZKld0tgYmAABc HTTP/1.1" 200 269 0.000791
(11137) accepted ('192.168.0.163', 53459)
192.168.0.163 - - [08/Aug/2023 15:11:44] "GET /socket.io/?EIO=4&transport=polling&t=OdLj3OM&sid=IQl7g7aZKld0tgYmAABc HTTP/1.1" 200 237 0.000521
192.168.0.163 - - [08/Aug/2023 15:11:47] "GET /socket.io/?EIO=4&transport=polling&t=OdLj46N HTTP/1.1" 200 334 0.002502
Client connected
192.168.0.163 - - [08/Aug/2023 15:11:47] "POST /socket.io/?EIO=4&transport=polling&t=OdLj46n&sid=yvHGCciJ0W7xnNnAAABe HTTP/1.1" 200 223 0.003354
192.168.0.163 - - [08/Aug/2023 15:11:47] "GET /socket.io/?EIO=4&transport=polling&t=OdLj46o&sid=yvHGCciJ0W7xnNnAAABe HTTP/1.1" 200 269 0.001139
(11137) accepted ('192.168.0.163', 53469)
192.168.0.163 - - [08/Aug/2023 15:11:47] "GET /socket.io/?EIO=4&transport=polling&t=OdLj470&sid=yvHGCciJ0W7xnNnAAABe HTTP/1.1" 200 237 0.000995
192.168.0.163 - - [08/Aug/2023 15:11:47] "GET /socket.io/?EIO=4&transport=polling&t=OdLj478&sid=yvHGCciJ0W7xnNnAAABe HTTP/1.1" 200 237 0.000471
192.168.0.163 - - [08/Aug/2023 15:11:50] "GET /socket.io/?EIO=4&transport=polling&t=OdLj4rG HTTP/1.1" 200 334 0.002346
Client connected
192.168.0.163 - - [08/Aug/2023 15:11:50] "POST /socket.io/?EIO=4&transport=polling&t=OdLj4re&sid=whjNXNF1fxP0ALzoAABg HTTP/1.1" 200 223 0.003343
(11137) accepted ('192.168.0.163', 53483)
192.168.0.163 - - [08/Aug/2023 15:11:50] "GET /socket.io/?EIO=4&transport=polling&t=OdLj4rf&sid=whjNXNF1fxP0ALzoAABg HTTP/1.1" 200 269 0.001593
192.168.0.163 - - [08/Aug/2023 15:11:50] "GET /socket.io/?EIO=4&transport=polling&t=OdLj4rt&sid=whjNXNF1fxP0ALzoAABg HTTP/1.1" 200 237 0.000644
192.168.0.163 - - [08/Aug/2023 15:11:50] "GET /socket.io/?EIO=4&transport=polling&t=OdLj4r_&sid=whjNXNF1fxP0ALzoAABg HTTP/1.1" 200 237 0.000649
192.168.0.163 - - [08/Aug/2023 15:11:53] "GET /socket.io/?EIO=4&transport=polling&t=OdLj5aB HTTP/1.1" 200 334 0.001117
Client connected
192.168.0.163 - - [08/Aug/2023 15:11:53] "POST /socket.io/?EIO=4&transport=polling&t=OdLj5aP&sid=h-X6Aw4YsFBTn2HfAABi HTTP/1.1" 200 223 0.001594
192.168.0.163 - - [08/Aug/2023 15:11:53] "GET /socket.io/?EIO=4&transport=polling&t=OdLj5aP.0&sid=h-X6Aw4YsFBTn2HfAABi HTTP/1.1" 200 269 0.000485
(11137) accepted ('192.168.0.163', 53517)
192.168.0.163 - - [08/Aug/2023 15:11:53] "GET /socket.io/?EIO=4&transport=polling&t=OdLj5ab&sid=h-X6Aw4YsFBTn2HfAABi HTTP/1.1" 200 237 0.000454
192.168.0.163 - - [08/Aug/2023 15:11:53] "GET /socket.io/?EIO=4&transport=polling&t=OdLj5ai&sid=h-X6Aw4YsFBTn2HfAABi HTTP/1.1" 200 237 0.000449
英文:
I currently have a React component that will connect to a web socket and print out the data received line by line. On the server side, my Flask app will start a background thread to emit a test message every 3 seconds.
Each time the server emits a message, the connect() event looks like it gets called. Is this expected? Or could it be related to the React component?
React component
const OutputWindow: React.FC = () => {
const socket = io('http://localhost:5000');
const [socketData, setSocketData] = useState<string[]>([]);
useEffect(() => {
socket.on('connect', () => {
console.log('Connect established');
})
socket.on('server_data', (data) => {
console.log('Receved data from server! ' + data);
setSocketData(prevSocketData => [...prevSocketData, data]);
})
}, []);
return (
<div className="window">
{socketData.map((line, index) => (
<p className="log-line" key={index}>
{line}
</p>
))}
</div>
);
};
Flask server that emits a test message every 3 seconds
log_thread=None
thread_lock = threading.Lock()
@socketio.on('connect')
def handle_connect():
print(f'Client connected')
# Start thread that will emit log file data
global log_thread
with thread_lock:
if log_thread is None:
log_thread = socketio.start_background_task(send_data)
@socketio.on('disconnect')
def handle_disconnect():
print(f'A client disconnected')
def send_data():
print("Streaming thread started.")
while True:
socketio.emit("server_data", "test message")
socketio.sleep(3)
Server side logs:
Client connected
192.168.0.163 - - [08/Aug/2023 15:11:44] "POST /socket.io/?EIO=4&transport=polling&t=OdLj3O8&sid=IQl7g7aZKld0tgYmAABc HTTP/1.1" 200 223 0.002163
192.168.0.163 - - [08/Aug/2023 15:11:44] "GET /socket.io/?EIO=4&transport=polling&t=OdLj3O9&sid=IQl7g7aZKld0tgYmAABc HTTP/1.1" 200 269 0.000791
(11137) accepted ('192.168.0.163', 53459)
192.168.0.163 - - [08/Aug/2023 15:11:44] "GET /socket.io/?EIO=4&transport=polling&t=OdLj3OM&sid=IQl7g7aZKld0tgYmAABc HTTP/1.1" 200 237 0.000521
192.168.0.163 - - [08/Aug/2023 15:11:47] "GET /socket.io/?EIO=4&transport=polling&t=OdLj46N HTTP/1.1" 200 334 0.002502
Client connected
192.168.0.163 - - [08/Aug/2023 15:11:47] "POST /socket.io/?EIO=4&transport=polling&t=OdLj46n&sid=yvHGCciJ0W7xnNnAAABe HTTP/1.1" 200 223 0.003354
192.168.0.163 - - [08/Aug/2023 15:11:47] "GET /socket.io/?EIO=4&transport=polling&t=OdLj46o&sid=yvHGCciJ0W7xnNnAAABe HTTP/1.1" 200 269 0.001139
(11137) accepted ('192.168.0.163', 53469)
192.168.0.163 - - [08/Aug/2023 15:11:47] "GET /socket.io/?EIO=4&transport=polling&t=OdLj470&sid=yvHGCciJ0W7xnNnAAABe HTTP/1.1" 200 237 0.000995
192.168.0.163 - - [08/Aug/2023 15:11:47] "GET /socket.io/?EIO=4&transport=polling&t=OdLj478&sid=yvHGCciJ0W7xnNnAAABe HTTP/1.1" 200 237 0.000471
192.168.0.163 - - [08/Aug/2023 15:11:50] "GET /socket.io/?EIO=4&transport=polling&t=OdLj4rG HTTP/1.1" 200 334 0.002346
Client connected
192.168.0.163 - - [08/Aug/2023 15:11:50] "POST /socket.io/?EIO=4&transport=polling&t=OdLj4re&sid=whjNXNF1fxP0ALzoAABg HTTP/1.1" 200 223 0.003343
(11137) accepted ('192.168.0.163', 53483)
192.168.0.163 - - [08/Aug/2023 15:11:50] "GET /socket.io/?EIO=4&transport=polling&t=OdLj4rf&sid=whjNXNF1fxP0ALzoAABg HTTP/1.1" 200 269 0.001593
192.168.0.163 - - [08/Aug/2023 15:11:50] "GET /socket.io/?EIO=4&transport=polling&t=OdLj4rt&sid=whjNXNF1fxP0ALzoAABg HTTP/1.1" 200 237 0.000644
192.168.0.163 - - [08/Aug/2023 15:11:50] "GET /socket.io/?EIO=4&transport=polling&t=OdLj4r_&sid=whjNXNF1fxP0ALzoAABg HTTP/1.1" 200 237 0.000649
192.168.0.163 - - [08/Aug/2023 15:11:53] "GET /socket.io/?EIO=4&transport=polling&t=OdLj5aB HTTP/1.1" 200 334 0.001117
Client connected
192.168.0.163 - - [08/Aug/2023 15:11:53] "POST /socket.io/?EIO=4&transport=polling&t=OdLj5aP&sid=h-X6Aw4YsFBTn2HfAABi HTTP/1.1" 200 223 0.001594
192.168.0.163 - - [08/Aug/2023 15:11:53] "GET /socket.io/?EIO=4&transport=polling&t=OdLj5aP.0&sid=h-X6Aw4YsFBTn2HfAABi HTTP/1.1" 200 269 0.000485
(11137) accepted ('192.168.0.163', 53517)
192.168.0.163 - - [08/Aug/2023 15:11:53] "GET /socket.io/?EIO=4&transport=polling&t=OdLj5ab&sid=h-X6Aw4YsFBTn2HfAABi HTTP/1.1" 200 237 0.000454
192.168.0.163 - - [08/Aug/2023 15:11:53] "GET /socket.io/?EIO=4&transport=polling&t=OdLj5ai&sid=h-X6Aw4YsFBTn2HfAABi HTTP/1.1" 200 237 0.000449
答案1
得分: 0
这可能是因为你更新了socketData
状态,导致组件重新渲染,并且打开了新的连接const socket = io('http://localhost:5000');
。
我会确保使用useMemo
只建立一次连接。
import { useMemo } from 'react';
.
.
.
const socket = useMemo(() => {
return io('http://localhost:5000');
}, []);
另一种方法是创建一个上下文API,在组件首次渲染时将io()
返回的连接存储在状态中,然后可以在其他组件中使用该连接。
// 上下文API
import { createContext, useContext, useState, useEffect } from 'react';
// 其他导入
export const SocketContext = createContext();
export function useSocket() {
return useContext(SocketContext);
}
export default function SocketProvider({ children }) {
const [socket, setSocket] = useState(null);
useEffect(() => {
const connection = io('....');
setSocket(connection);
}, []); // 确保在第一次渲染时建立连接
return <SocketContext.Provider value={{ socket }}>{children}</SocketContext.Provider>;
}
// 添加到App.jsx或index.jsx
// 导入SocketProvider from ...
// 导入MyComponent from ...
export default function App() {
return (
<div className="App">
<SocketProvider>
<MyComponent />
</SocketProvider>
</div>
);
}
// 使用:
export function MyComponent() {
const { socket } = useSocket();
// ...你的状态
useEffect(() => {
/*
...你的代码...
socket.on('connect', () => {
console.log('连接已建立');
})
socket.on('server_data', (data) => {
console.log('从服务器接收到数据!' + data);
setSocketData(prevSocketData => [...prevSocketData, data]);
})
*/
}, [socket]); // 由于连接已建立并且`socket`状态已更改,它将包含连接,并且此useEffect仅在首次渲染上下文API组件时调用一次,因为`socket`状态只会更改1次(在首次渲染时)。
return /* ... */
}
英文:
This can be because your components gets re-rendered since you update your socketData
state, and then a new connection gets opened const socket = io('http://localhost:5000');
I will personally make sure this connection is made once, using useMemo
import { useMemo } from 'react';
.
.
.
const socket = useMemo(() => {
return io('http://localhost:5000');
}, []);
https://react.dev/reference/react/useMemo
Another way is to create a Context API and for the first time the component gets render, you store in a state the connection returned from io()
and then you can use the connection in other components.
// Context API
import {createContext, useContext, useState, useEffect} from 'react';
// other impots
export const SocketContext = createContext();
export function useSocket() {
return useContext(SocketContext);
}
export default function SocketProvider({ children }) {
const [socket, setSocket] = useState(null);
useEffect(() => {
const connection = io('....');
setSocket(connection);
}, []); // make sure the connection is first made on the first render
return <SocketContext.Provider value={{ socket }}>{children}</SocketContext.Provider>
}
// add to App.jsx or index.jsx
// import SocketProvider from ...
// import MyComponent from ...
export default function App() {
return (
<div className="App">
<SocketProvider>
<MyComponent />
<SocketProvider>
</div>
);
}
// usage:
export function MyComponent() {
const { socket } = useSocket();
// ... your states
useEffect(() => {
/*
... your code ...
socket.on('connect', () => {
console.log('Connect established');
})
socket.on('server_data', (data) => {
console.log('Receved data from server! ' + data);
setSocketData(prevSocketData => [...prevSocketData, data]);
})
*/
}, [socket]); // since connection was made and `socket` state changed, it will contain the connection and this useEffect will be called only once, since `socket` state will change only 1 time (on first rendered in the context api component)
return /* ... */
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论