文章目錄
- 一、Socket.IO庫簡單使用說明
- 1. 后端 Flask + Flask-SocketIO
- 2. Android 客戶端集成 Socket.IO
- 3. 布局文件
- 注意事項
- 二、接受服務器消息的二種方法
- 1. 客戶端接收通過 `emit` 發送的消息
- 功能
- 使用場景
- 后端代碼(Flask-SocketIO)
- 客戶端代碼(Android Studio,Java)
- 2. 客戶端接收通過 `return` 發送的響應
- 功能
- 使用場景
- 后端代碼(Flask-SocketIO)
- 客戶端代碼(Android Studio,Java)
- 4. 二者的區別
- 拓展:room與namespace
- 命名空間(Namespace)
- 功能示例
- 房間(Rooms)
- 功能示例
- 總結
- 拓展:
Socket.IO 是一個流行的實時通信庫,支持 WebSocket 和其他回退機制(如長輪詢),能夠在客戶端和服務器之間實現低延遲的雙向通信。
一、Socket.IO庫簡單使用說明
1. 后端 Flask + Flask-SocketIO
首先,確保你的 Flask 后端已經安裝了 Flask-SocketIO
。你可以通過以下命令安裝:
pip install Flask Flask-SocketIO
以下是一個簡單的 Flask 后端示例代碼:
from flask import Flask
from flask_socketio import SocketIO, emitapp = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key'
socketio = SocketIO(app)@app.route('/')
def index():return "Hello, World!"@socketio.on('message')
def handle_message(msg):print('Received message: ' + msg)emit('response', 'Echo: ' + msg, broadcast=True)if __name__ == '__main__':socketio.run(app, debug=True)
2. Android 客戶端集成 Socket.IO
在 Android Studio 中,你需要添加 Socket.IO 的依賴。在 build.gradle
文件中添加以下內容:
dependencies {implementation 'io.socket:socket.io-client:1.4.0'
}
確保你的應用有網絡權限。在 AndroidManifest.xml
文件中添加以下內容:
<uses-permission android:name="android.permission.INTERNET" />
以下是一個簡單的 Android 客戶端示例:
import io.socket.client.IO;
import io.socket.client.Socket;
import io.socket.emitter.Emitter;public class MainActivity extends AppCompatActivity {private Socket socket;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);try {socket = IO.socket("http://yourserver.com/socket.io");socket.connect();socket.on("response", new Emitter.Listener() {@Overridepublic void call(Object... args) {runOnUiThread(new Runnable() {@Overridepublic void run() {TextView messagesView = findViewById(R.id.messagesView);messagesView.append((String) args[0] + "\n");}});}});Button sendButton = findViewById(R.id.sendButton);sendButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {EditText messageInput = findViewById(R.id.messageInput);String message = messageInput.getText().toString();if (!message.isEmpty()) {socket.emit("message", message);messageInput.setText("");}}});} catch (Exception e) {e.printStackTrace();}}@Overrideprotected void onDestroy() {super.onDestroy();socket.disconnect();}
}
3. 布局文件
在 res/layout/activity_main.xml
中定義一個簡單的布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:padding="16dp"><EditTextandroid:id="@+id/messageInput"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="Type a message" /><Buttonandroid:id="@+id/sendButton"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Send" /><TextViewandroid:id="@+id/messagesView"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="Messages will appear here"android:textSize="16sp" /></LinearLayout>
socket.on
和 socket.emit
特性 | socket.on | socket.emit |
---|---|---|
功能 | 監聽來自服務器的事件 | 向服務器發送事件 |
方向 | 從服務器到客戶端 | 從客戶端到服務器 |
回調 | 注冊回調函數以處理接收到的事件 | 可選地注冊回調函數以接收服務器的響應 |
使用場景 | 接收服務器推送的消息,如通知、廣播等 | 發送請求到服務器,如提交數據、請求信息等 |
注意事項
- 服務器地址:確保在 Android 客戶端中使用的服務器地址與 Flask 后端的地址一致。
- 網絡權限:確保在
AndroidManifest.xml
中添加了網絡權限。 - 線程安全:在回調函數中更新 UI 時,確保使用
runOnUiThread
。
二、接受服務器消息的二種方法
emit
:- 后端:使用
emit
發送事件和數據。 - 客戶端:通過
socket.on
監聽事件并接收數據。
- 后端:使用
return
:- 后端:在事件處理函數中使用
return
發送響應。 - 客戶端:通過
emit
方法的回調函數接收響應。
- 后端:在事件處理函數中使用
1. 客戶端接收通過 emit
發送的消息
當后端使用 emit
發送消息時,客戶端可以通過 socket.on
監聽對應的事件來接收消息。
功能
- 顯式發送事件:
emit
可以發送自定義事件,并攜帶數據。 - 廣播或單播:可以指定發送給所有客戶端,或者特定的客戶端。
使用場景
- 廣播消息:向所有連接的客戶端發送消息。
- 單播消息:向特定的客戶端發送消息。
- 復雜交互:需要發送多個事件或不同類型的數據時。
后端代碼(Flask-SocketIO)
from flask import Flask
from flask_socketio import SocketIO, emitapp = Flask(__name__)
socketio = SocketIO(app)@socketio.on('client_message')
def handle_client_message(data):print("Received message:", data)emit('server_message', 'Hello from Server!') # 使用 emit 發送消息if __name__ == '__main__':socketio.run(app, host='0.0.0.0', port=5000)
客戶端代碼(Android Studio,Java)
import io.socket.client.IO;
import io.socket.client.Socket;
import io.socket.emitter.Emitter;public class MainActivity extends AppCompatActivity {private Socket mSocket;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);try {mSocket = IO.socket("http://your-server-address:5000");mSocket.connect();// 監聽服務器通過 emit 發送的消息mSocket.on("server_message", new Emitter.Listener() {@Overridepublic void call(Object... args) {String message = (String) args[0];runOnUiThread(() -> {Toast.makeText(MainActivity.this, "Received via emit: " + message, Toast.LENGTH_SHORT).show();});}});} catch (Exception e) {e.printStackTrace();}}@Overrideprotected void onDestroy() {super.onDestroy();mSocket.disconnect();mSocket.off("server_message");}
}
2. 客戶端接收通過 return
發送的響應
當后端使用 return
發送響應時,客戶端可以通過 emit
方法的回調函數接收響應。
功能
- 返回響應:直接返回一個值或字符串。
- 簡單交互:適用于簡單的場景,客戶端不需要復雜的消息交互。
使用場景
- 簡單響應:客戶端只需要一個簡單的響應,例如確認消息已接收。
- 快速反饋:快速返回一個結果,不需要額外的事件處理。
后端代碼(Flask-SocketIO)
from flask import Flask
from flask_socketio import SocketIOapp = Flask(__name__)
socketio = SocketIO(app)@socketio.on('client_message')
def handle_client_message(data):print("Received message:", data)return 'Server received your message!' # 使用 return 發送響應if __name__ == '__main__':socketio.run(app, host='0.0.0.0', port=5000)
客戶端代碼(Android Studio,Java)
import io.socket.client.IO;
import io.socket.client.Socket;
import io.socket.emitter.Emitter;public class MainActivity extends AppCompatActivity {private Socket mSocket;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);try {mSocket = IO.socket("http://your-server-address:5000");mSocket.connect();// 發送消息并接收通過 return 發送的響應mSocket.emit("client_message", "Hello from Android!", new Emitter.Ack() {@Overridepublic void call(Object... args) {if (args.length > 0) {String response = (String) args[0];runOnUiThread(() -> {Toast.makeText(MainActivity.this, "Received via return: " + response, Toast.LENGTH_SHORT).show();});}}});} catch (Exception e) {e.printStackTrace();}}@Overrideprotected void onDestroy() {super.onDestroy();mSocket.disconnect();}
}
4. 二者的區別
特性 | emit | return |
---|---|---|
功能 | 顯式發送事件,攜帶數據 | 直接返回響應 |
方向 | 從服務器到客戶端 | 從服務器到客戶端 |
使用場景 | 廣播或單播消息,復雜交互 | 簡單響應,快速反饋 |
示例 | emit('server_message', 'Hello from Server!') | return 'Server received your message!' |
- 如果你需要向客戶端發送復雜的事件或廣播消息,使用
emit
。 - 如果客戶端只需要一個簡單的響應,使用
return
。
拓展:room與namespace
在 Flask-SocketIO 中,命名空間(Namespace)和房間(Rooms)是兩個非常重要的功能,它們可以更好地組織和管理實時通信。
命名空間(Namespace)
命名空間允許在同一個 Socket.IO 服務器上創建多個獨立的通信通道。每個命名空間都可以有自己的事件和邏輯,互不干擾。這在大型應用中非常有用,可以將不同的功能模塊分開,例如聊天功能和通知功能。
功能示例
from flask_socketio import emit@socketio.on('message', namespace='/chat')
def handle_chat_message(msg):emit('message', msg, broadcast=True, namespace='/chat')@socketio.on('notification', namespace='/notifications')
def handle_notification(msg):emit('notification', msg, broadcast=True, namespace='/notifications')
在上面的代碼中,/chat
和 /notifications
是兩個不同的命名空間,分別用于處理聊天消息和通知。
房間(Rooms)
房間是命名空間的進一步細分,允許將用戶分組,以便向特定的用戶組發送消息。這在聊天室、多人游戲等場景中非常有用。
功能示例
from flask_socketio import join_room, leave_room@socketio.on('join')
def on_join(data):username = data['username']room = data['room']join_room(room)send(username + ' has entered the room.', to=room)@socketio.on('leave')
def on_leave(data):username = data['username']room = data['room']leave_room(room)send(username + ' has left the room.', to=room)
在上面的代碼中,join_room
和 leave_room
函數用于管理用戶加入和離開房間。send
函數的 to
參數用于指定消息發送到的房間。
總結
- 命名空間:用于創建獨立的通信通道,適合將不同的功能模塊分開。
- 房間:用于將用戶分組,適合向特定用戶組發送消息。
通過合理使用命名空間和房間,可以構建更加模塊化和高效的實時通信應用。
拓展:
room功能實現用戶之間消息的發送