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

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

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 = () =&gt; {
    const socket = io(&#39;http://localhost:5000&#39;);
    const [socketData, setSocketData] = useState&lt;string[]&gt;([]);

    useEffect(() =&gt; {
        socket.on(&#39;connect&#39;, () =&gt; {
            console.log(&#39;Connect established&#39;);
        })

        socket.on(&#39;server_data&#39;, (data) =&gt; {
            console.log(&#39;Receved data from server! &#39; + data);
            setSocketData(prevSocketData =&gt; [...prevSocketData, data]);
        })
    }, []);

    return (
            &lt;div className=&quot;window&quot;&gt; 
            {socketData.map((line, index) =&gt; (
                &lt;p className=&quot;log-line&quot; key={index}&gt;
                    {line}
                &lt;/p&gt;
            ))}
            &lt;/div&gt;
    );
};

Flask server that emits a test message every 3 seconds

log_thread=None
thread_lock = threading.Lock()

@socketio.on(&#39;connect&#39;)
def handle_connect():
    print(f&#39;Client connected&#39;)

    # 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(&#39;disconnect&#39;)
def handle_disconnect():
    print(f&#39;A client disconnected&#39;)


def send_data():
    print(&quot;Streaming thread started.&quot;)

    while True:
        socketio.emit(&quot;server_data&quot;, &quot;test message&quot;)
        socketio.sleep(3)

Server side logs:

Client connected
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
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
(11137) accepted (&#39;192.168.0.163&#39;, 53459)
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
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
Client connected
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
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
(11137) accepted (&#39;192.168.0.163&#39;, 53469)
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
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
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
Client connected
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
(11137) accepted (&#39;192.168.0.163&#39;, 53483)
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
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
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
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
Client connected
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
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
(11137) accepted (&#39;192.168.0.163&#39;, 53517)
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
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只建立一次连接。

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

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

import { useMemo } from &#39;react&#39;;
.
.
.
const socket = useMemo(() =&gt; {
return io(&#39;http://localhost:5000&#39;);
}, []);

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 &#39;react&#39;;
// other impots
export const SocketContext = createContext();
export function useSocket() {
return useContext(SocketContext);
}
export default function SocketProvider({ children }) {
const [socket, setSocket] = useState(null);
useEffect(() =&gt; {
const connection = io(&#39;....&#39;);
setSocket(connection);
}, []); // make sure the connection is first made on the first render
return &lt;SocketContext.Provider value={{ socket }}&gt;{children}&lt;/SocketContext.Provider&gt;
}
// add to App.jsx or index.jsx
// import SocketProvider from ...
// import MyComponent from ...
export default function App() {
return (
&lt;div className=&quot;App&quot;&gt;
&lt;SocketProvider&gt;
&lt;MyComponent /&gt;
&lt;SocketProvider&gt;
&lt;/div&gt;
);
}
// usage:
export function MyComponent() {
const { socket } = useSocket();
// ... your states
useEffect(() =&gt; {
/*
... your code ...
socket.on(&#39;connect&#39;, () =&gt; {
console.log(&#39;Connect established&#39;);
})
socket.on(&#39;server_data&#39;, (data) =&gt; {
console.log(&#39;Receved data from server! &#39; + data);
setSocketData(prevSocketData =&gt; [...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 /* ... */
}

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:

确定