资料补充
:
1、grpc在dart中的插件:https://pub.dev/packages/grpc
2、grpc的示例程序:https://github.com/grpc/grpc-dart/tree/master/example
如标题,假设现在已有grpc client/server程序。我这里的逻辑比较简单,基于ip地址的简单限制访问,但是允许来自一个ip地址的多次访问。
具体的实现逻辑在于,当接收到一个来自 client 的 grpc 接口访问,则优先获取client的ip信息:
如果和之前连接的IP地址相同或者之前还未有已连接的client,则允许连接并访问server;
否则,新的连接请求会收到 "Server is already handling another client" 错误;
当已连接的客户端断开连接时,连接计数会正确减少,允许新的client连接。
step1、
导入需要的插件 .dart。
dart
synchronized: ^3.1.0
import 'dart:async';
import 'dart:io';
import 'package:grpc/grpc.dart';
import 'package:synchronized/synchronized.dart';
step2、
增加一个连接管理的类。
dart
// 添加连接计数器和锁
int _activeConnections = 0;
String? _currentClientIP; // 记录当前连接的客户端IP
final _connectionLock = Lock();
// 创建连接管理器
class ConnectionManager {
static String _getClientIP(ServiceCall call) {
try {
// 尝试从客户端元数据中获取IP
if (call.clientMetadata != null) {
// 检查X-Forwarded-For头(用于代理场景)
final forwardedFor = call.clientMetadata!['x-forwarded-for'];
if (forwardedFor != null && forwardedFor.isNotEmpty) {
return forwardedFor;
}
// 检查X-Real-IP头(某些代理服务器使用)
final realIP = call.clientMetadata!['x-real-ip'];
if (realIP != null && realIP.isNotEmpty) {
return realIP;
}
}
// 尝试从远程地址获取IP(直接连接场景)
if (call.remoteAddress != null) {
return call.remoteAddress.toString();
}
} catch (e) {
print('Error getting client IP: $e');
}
return 'Unknown IP';
}
static Future<void> checkConnection(ServiceCall call) async {
bool canConnect = false;
String clientIP = _getClientIP(call);
await _connectionLock.synchronized(() {
if (_activeConnections == 0) {
// 没有活动连接,允许新连接
_activeConnections++;
_currentClientIP = clientIP;
canConnect = true;
print('New client connected from IP: $clientIP. Active connections: $_activeConnections');
} else if (clientIP == _currentClientIP) {
// 相同IP的客户端,允许连接
_activeConnections++;
canConnect = true;
print('Additional connection from same IP: $clientIP. Active connections: $_activeConnections');
} else {
// 不同IP的客户端,拒绝连接
print('Connection rejected for client IP: $clientIP - server is handling client from IP: $_currentClientIP');
}
});
if (!canConnect) {
throw GrpcError.unavailable(
'Server is already handling another client from different IP');
}
}
static Future<void> releaseConnection(ServiceCall call) async {
String clientIP = _getClientIP(call);
await _connectionLock.synchronized(() {
if (_activeConnections > 0) {
_activeConnections--;
print('Client disconnected from IP: $clientIP. Active connections: $_activeConnections');
// 如果没有活动连接了,清除当前客户端IP
if (_activeConnections == 0) {
_currentClientIP = null;
print('All connections closed, ready for new clients');
}
}
});
}
}
step3、
在client发送grpc请求后,server端在服务类的实际操作函类前后加上连接管理类的判断,以及不符后的连接清除处理。
dart
// 给XXXService添加连接限制
class ConnectionLimitedXXXService extends XXXServiceBase {
@override
Future<StringReply> usrFunCallReq(
ServiceCall call, StringRequest request) async {
await ConnectionManager.checkConnection(call); // 增加连接判断处理
try {
// procedure
return StringReply()
..message = jsonEncode(xxx);
} finally {
await ConnectionManager.releaseConnection(call); // 增加连接清除处理
}
}
...
}