文章目录
- 一、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, emit
app = 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;
@Override
protected 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() {
@Override
public void call(Object... args) {
runOnUiThread(new Runnable() {
@Override
public 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() {
@Override
public 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();
}
}
@Override
protected 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">
<EditText
android:id="@+id/messageInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Type a message" />
<Button
android:id="@+id/sendButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Send" />
<TextView
android: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, emit
app = 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;
@Override
protected 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() {
@Override
public 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();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
mSocket.disconnect();
mSocket.off("server_message");
}
}
2. 客户端接收通过 return
发送的响应
当后端使用 return
发送响应时,客户端可以通过 emit
方法的回调函数接收响应。
功能
- 返回响应:直接返回一个值或字符串。
- 简单交互:适用于简单的场景,客户端不需要复杂的消息交互。
使用场景
- 简单响应:客户端只需要一个简单的响应,例如确认消息已接收。
- 快速反馈:快速返回一个结果,不需要额外的事件处理。
后端代码(Flask-SocketIO)
from flask import Flask
from flask_socketio import SocketIO
app = 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;
@Override
protected 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() {
@Override
public 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();
}
}
@Override
protected 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功能实现用户之间消息的发送