为什么每次发出消息时,我的Flask服务器的SocketIO连接事件都会被调用?

huangapple go评论130阅读模式
英文:

Why is my flask server socketio connect event being called each time a message is emitted?

问题

我目前有一个React组件,它将连接到一个Web套接字并逐行打印接收到的数据。在服务器端,我的Flask应用程序将启动一个后台线程,每3秒发送一条测试消息。

每次服务器发出消息时,似乎都会调用connect()事件。这是预期的吗?还是与React组件有关?

React组件

  1. const OutputWindow: React.FC = () => {
  2. const socket = io('http://localhost:5000');
  3. const [socketData, setSocketData] = useState<string[]>([]);
  4. useEffect(() => {
  5. socket.on('connect', () => {
  6. console.log('Connect established');
  7. })
  8. socket.on('server_data', (data) => {
  9. console.log('Received data from server! ' + data);
  10. setSocketData(prevSocketData => [...prevSocketData, data]);
  11. })
  12. }, []);
  13. return (
  14. <div className="window">
  15. {socketData.map((line, index) => (
  16. <p className="log-line" key={index}>
  17. {line}
  18. </p>
  19. ))}
  20. </div>
  21. );
  22. };

Flask服务器每3秒发送一条测试消息的代码:

  1. log_thread = None
  2. thread_lock = threading.Lock()
  3. @socketio.on('connect')
  4. def handle_connect():
  5. print('Client connected')
  6. # 启动线程以发送日志文件数据
  7. global log_thread
  8. with thread_lock:
  9. if log_thread is None:
  10. log_thread = socketio.start_background_task(send_data)
  11. @socketio.on('disconnect')
  12. def handle_disconnect():
  13. print('A client disconnected')
  14. def send_data():
  15. print("Streaming thread started.")
  16. while True:
  17. socketio.emit("server_data", "test message")
  18. socketio.sleep(3)

服务器端日志:

  1. Client connected
  2. 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
  3. 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
  4. (11137) accepted ('192.168.0.163', 53459)
  5. 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
  6. 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
  7. Client connected
  8. 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
  9. 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
  10. (11137) accepted ('192.168.0.163', 53469)
  11. 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
  12. 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
  13. 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
  14. Client connected
  15. 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
  16. (11137) accepted ('192.168.0.163', 53483)
  17. 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
  18. 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
  19. 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
  20. 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
  21. Client connected
  22. 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
  23. 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
  24. (11137) accepted ('192.168.0.163', 53517)
  25. 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
  26. 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

  1. const OutputWindow: React.FC = () =&gt; {
  2. const socket = io(&#39;http://localhost:5000&#39;);
  3. const [socketData, setSocketData] = useState&lt;string[]&gt;([]);
  4. useEffect(() =&gt; {
  5. socket.on(&#39;connect&#39;, () =&gt; {
  6. console.log(&#39;Connect established&#39;);
  7. })
  8. socket.on(&#39;server_data&#39;, (data) =&gt; {
  9. console.log(&#39;Receved data from server! &#39; + data);
  10. setSocketData(prevSocketData =&gt; [...prevSocketData, data]);
  11. })
  12. }, []);
  13. return (
  14. &lt;div className=&quot;window&quot;&gt;
  15. {socketData.map((line, index) =&gt; (
  16. &lt;p className=&quot;log-line&quot; key={index}&gt;
  17. {line}
  18. &lt;/p&gt;
  19. ))}
  20. &lt;/div&gt;
  21. );
  22. };

Flask server that emits a test message every 3 seconds

  1. log_thread=None
  2. thread_lock = threading.Lock()
  3. @socketio.on(&#39;connect&#39;)
  4. def handle_connect():
  5. print(f&#39;Client connected&#39;)
  6. # Start thread that will emit log file data
  7. global log_thread
  8. with thread_lock:
  9. if log_thread is None:
  10. log_thread = socketio.start_background_task(send_data)
  11. @socketio.on(&#39;disconnect&#39;)
  12. def handle_disconnect():
  13. print(f&#39;A client disconnected&#39;)
  14. def send_data():
  15. print(&quot;Streaming thread started.&quot;)
  16. while True:
  17. socketio.emit(&quot;server_data&quot;, &quot;test message&quot;)
  18. socketio.sleep(3)

Server side logs:

  1. Client connected
  2. 192.168.0.163 - - [08/Aug/2023 15:11:44] &quot;POST /socket.io/?EIO=4&amp;transport=polling&amp;t=OdLj3O8&amp;sid=IQl7g7aZKld0tgYmAABc HTTP/1.1&quot; 200 223 0.002163
  3. 192.168.0.163 - - [08/Aug/2023 15:11:44] &quot;GET /socket.io/?EIO=4&amp;transport=polling&amp;t=OdLj3O9&amp;sid=IQl7g7aZKld0tgYmAABc HTTP/1.1&quot; 200 269 0.000791
  4. (11137) accepted (&#39;192.168.0.163&#39;, 53459)
  5. 192.168.0.163 - - [08/Aug/2023 15:11:44] &quot;GET /socket.io/?EIO=4&amp;transport=polling&amp;t=OdLj3OM&amp;sid=IQl7g7aZKld0tgYmAABc HTTP/1.1&quot; 200 237 0.000521
  6. 192.168.0.163 - - [08/Aug/2023 15:11:47] &quot;GET /socket.io/?EIO=4&amp;transport=polling&amp;t=OdLj46N HTTP/1.1&quot; 200 334 0.002502
  7. Client connected
  8. 192.168.0.163 - - [08/Aug/2023 15:11:47] &quot;POST /socket.io/?EIO=4&amp;transport=polling&amp;t=OdLj46n&amp;sid=yvHGCciJ0W7xnNnAAABe HTTP/1.1&quot; 200 223 0.003354
  9. 192.168.0.163 - - [08/Aug/2023 15:11:47] &quot;GET /socket.io/?EIO=4&amp;transport=polling&amp;t=OdLj46o&amp;sid=yvHGCciJ0W7xnNnAAABe HTTP/1.1&quot; 200 269 0.001139
  10. (11137) accepted (&#39;192.168.0.163&#39;, 53469)
  11. 192.168.0.163 - - [08/Aug/2023 15:11:47] &quot;GET /socket.io/?EIO=4&amp;transport=polling&amp;t=OdLj470&amp;sid=yvHGCciJ0W7xnNnAAABe HTTP/1.1&quot; 200 237 0.000995
  12. 192.168.0.163 - - [08/Aug/2023 15:11:47] &quot;GET /socket.io/?EIO=4&amp;transport=polling&amp;t=OdLj478&amp;sid=yvHGCciJ0W7xnNnAAABe HTTP/1.1&quot; 200 237 0.000471
  13. 192.168.0.163 - - [08/Aug/2023 15:11:50] &quot;GET /socket.io/?EIO=4&amp;transport=polling&amp;t=OdLj4rG HTTP/1.1&quot; 200 334 0.002346
  14. Client connected
  15. 192.168.0.163 - - [08/Aug/2023 15:11:50] &quot;POST /socket.io/?EIO=4&amp;transport=polling&amp;t=OdLj4re&amp;sid=whjNXNF1fxP0ALzoAABg HTTP/1.1&quot; 200 223 0.003343
  16. (11137) accepted (&#39;192.168.0.163&#39;, 53483)
  17. 192.168.0.163 - - [08/Aug/2023 15:11:50] &quot;GET /socket.io/?EIO=4&amp;transport=polling&amp;t=OdLj4rf&amp;sid=whjNXNF1fxP0ALzoAABg HTTP/1.1&quot; 200 269 0.001593
  18. 192.168.0.163 - - [08/Aug/2023 15:11:50] &quot;GET /socket.io/?EIO=4&amp;transport=polling&amp;t=OdLj4rt&amp;sid=whjNXNF1fxP0ALzoAABg HTTP/1.1&quot; 200 237 0.000644
  19. 192.168.0.163 - - [08/Aug/2023 15:11:50] &quot;GET /socket.io/?EIO=4&amp;transport=polling&amp;t=OdLj4r_&amp;sid=whjNXNF1fxP0ALzoAABg HTTP/1.1&quot; 200 237 0.000649
  20. 192.168.0.163 - - [08/Aug/2023 15:11:53] &quot;GET /socket.io/?EIO=4&amp;transport=polling&amp;t=OdLj5aB HTTP/1.1&quot; 200 334 0.001117
  21. Client connected
  22. 192.168.0.163 - - [08/Aug/2023 15:11:53] &quot;POST /socket.io/?EIO=4&amp;transport=polling&amp;t=OdLj5aP&amp;sid=h-X6Aw4YsFBTn2HfAABi HTTP/1.1&quot; 200 223 0.001594
  23. 192.168.0.163 - - [08/Aug/2023 15:11:53] &quot;GET /socket.io/?EIO=4&amp;transport=polling&amp;t=OdLj5aP.0&amp;sid=h-X6Aw4YsFBTn2HfAABi HTTP/1.1&quot; 200 269 0.000485
  24. (11137) accepted (&#39;192.168.0.163&#39;, 53517)
  25. 192.168.0.163 - - [08/Aug/2023 15:11:53] &quot;GET /socket.io/?EIO=4&amp;transport=polling&amp;t=OdLj5ab&amp;sid=h-X6Aw4YsFBTn2HfAABi HTTP/1.1&quot; 200 237 0.000454
  26. 192.168.0.163 - - [08/Aug/2023 15:11:53] &quot;GET /socket.io/?EIO=4&amp;transport=polling&amp;t=OdLj5ai&amp;sid=h-X6Aw4YsFBTn2HfAABi HTTP/1.1&quot; 200 237 0.000449

答案1

得分: 0

这可能是因为你更新了socketData状态,导致组件重新渲染,并且打开了新的连接const socket = io('http://localhost:5000');

我会确保使用useMemo只建立一次连接。

  1. import { useMemo } from 'react';
  2. .
  3. .
  4. .
  5. const socket = useMemo(() => {
  6. return io('http://localhost:5000');
  7. }, []);

另一种方法是创建一个上下文API,在组件首次渲染时将io()返回的连接存储在状态中,然后可以在其他组件中使用该连接。

  1. // 上下文API
  2. import { createContext, useContext, useState, useEffect } from 'react';
  3. // 其他导入
  4. export const SocketContext = createContext();
  5. export function useSocket() {
  6. return useContext(SocketContext);
  7. }
  8. export default function SocketProvider({ children }) {
  9. const [socket, setSocket] = useState(null);
  10. useEffect(() => {
  11. const connection = io('....');
  12. setSocket(connection);
  13. }, []); // 确保在第一次渲染时建立连接
  14. return <SocketContext.Provider value={{ socket }}>{children}</SocketContext.Provider>;
  15. }
  16. // 添加到App.jsx或index.jsx
  17. // 导入SocketProvider from ...
  18. // 导入MyComponent from ...
  19. export default function App() {
  20. return (
  21. <div className="App">
  22. <SocketProvider>
  23. <MyComponent />
  24. </SocketProvider>
  25. </div>
  26. );
  27. }
  28. // 使用:
  29. export function MyComponent() {
  30. const { socket } = useSocket();
  31. // ...你的状态
  32. useEffect(() => {
  33. /*
  34. ...你的代码...
  35. socket.on('connect', () => {
  36. console.log('连接已建立');
  37. })
  38. socket.on('server_data', (data) => {
  39. console.log('从服务器接收到数据!' + data);
  40. setSocketData(prevSocketData => [...prevSocketData, data]);
  41. })
  42. */
  43. }, [socket]); // 由于连接已建立并且`socket`状态已更改,它将包含连接,并且此useEffect仅在首次渲染上下文API组件时调用一次,因为`socket`状态只会更改1次(在首次渲染时)。
  44. return /* ... */
  45. }
英文:

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(&#39;http://localhost:5000&#39;);

I will personally make sure this connection is made once, using useMemo

  1. import { useMemo } from &#39;react&#39;;
  2. .
  3. .
  4. .
  5. const socket = useMemo(() =&gt; {
  6. return io(&#39;http://localhost:5000&#39;);
  7. }, []);

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.

  1. // Context API
  2. import {createContext, useContext, useState, useEffect} from &#39;react&#39;;
  3. // other impots
  4. export const SocketContext = createContext();
  5. export function useSocket() {
  6. return useContext(SocketContext);
  7. }
  8. export default function SocketProvider({ children }) {
  9. const [socket, setSocket] = useState(null);
  10. useEffect(() =&gt; {
  11. const connection = io(&#39;....&#39;);
  12. setSocket(connection);
  13. }, []); // make sure the connection is first made on the first render
  14. return &lt;SocketContext.Provider value={{ socket }}&gt;{children}&lt;/SocketContext.Provider&gt;
  15. }
  16. // add to App.jsx or index.jsx
  17. // import SocketProvider from ...
  18. // import MyComponent from ...
  19. export default function App() {
  20. return (
  21. &lt;div className=&quot;App&quot;&gt;
  22. &lt;SocketProvider&gt;
  23. &lt;MyComponent /&gt;
  24. &lt;SocketProvider&gt;
  25. &lt;/div&gt;
  26. );
  27. }
  28. // usage:
  29. export function MyComponent() {
  30. const { socket } = useSocket();
  31. // ... your states
  32. useEffect(() =&gt; {
  33. /*
  34. ... your code ...
  35. socket.on(&#39;connect&#39;, () =&gt; {
  36. console.log(&#39;Connect established&#39;);
  37. })
  38. socket.on(&#39;server_data&#39;, (data) =&gt; {
  39. console.log(&#39;Receved data from server! &#39; + data);
  40. setSocketData(prevSocketData =&gt; [...prevSocketData, data]);
  41. })
  42. */
  43. }, [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)
  44. return /* ... */
  45. }

huangapple
  • 本文由 发表于 2023年8月8日 22:57:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/76860776.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定