Flutter+WebRTC+gRPC开发点对点加密即时通讯APP--gRPC点对点通信
开篇
基于Flutter+WebRTC+gRPC,开发一款点对点加密、跨端、即时通讯APP,实现文字、音视频通话聊天,同时支持图片、短视频等文件传输功能,计划支持Windows、Android平台。我准备将自己的学习和实践过程记录下来,同时分享给大家,欢迎大家一起研讨交流。这个工程是利用自己的业余时间来实现的,不定时更新。本篇文章基于gRPC协议实现点对点通讯。

gRPC简介
RPC,全称Remote Procedure Call,中文译为远程过程调用。通俗地讲,使用RPC进行通信,调用远程函数就像调用本地函数一样,RPC底层会做好数据的序列化与传输,从而能使我们更轻松地创建分布式应用和服务。gRPC 是一种现代开源高性能远程过程调用 (RPC) 可以在任何环境中运行的框架。它可以有效地连接服务 在数据中心内和跨数据中心,支持对负载均衡、跟踪、 运行状况检查和身份验证。它也适用于最后一英里 分布式计算,将设备、移动应用程序和浏览器连接到 后端服务。gRPC是免费且开源的,由谷歌出品。
实现一个gRPC服务端和客户端,主要包含下边4步:
1.安装 protobuf 依赖
2.编写 proto 文件
3.编译 proto 文件
4.编写server端和编写client端
Dart语言下gRPC快速入门
Dart语言下使用gRPC前提条件包括,Dart 2.12 或更高版本 ,protoc版本 3,Dart 插件。
插件安装
Dart语言下安装protoc-gen-dart插件
shell
dart pub global activate protoc_plugin

安装完成后,记得将插件路径添加到系统路径。
插件路径:
shell
C:\Users\****\AppData\Local\Pub\Cache\bin
protoc安装与编辑
我们还需要安装protoc,并将路径添加到系统路径,protoc可以直接从Github下载。
接着,我们需要编辑我们的.proto文件,.proto
文件中为要序列化的每个数据结构添加消息,并指定名称和类型:
proto
syntax = "proto3";
package routeguide;
service RouteGuide {
rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
}
message RouteNote {
string message = 1;
}
syntax = "proto3" 说明proto为3版本。我们定义一个RouteGuide服务,其中包含RouteChat方法,我们使用双向流式RPC,就是说可以全双工通信,实现方式很简单,只需要在RouteChat的输入输出RouteNote前都加上stream即可。RouteNote就是我们的定义的请求和返回了。
编写完.proto文件后,使用下边的命令编译protobuf文件。
shell
protoc lib/protos/guide.proto --dart_out=grpc:.
--dart_out=grpc:.
指定输出路径,lib/protos/guide.proto
指定.proto文件位置。执行完命令后,我们就可以看到自动生成的Dart代码文件了,这些自动生成的文件,我们不要手动编辑哦。
dart
guide.pb.dart
guide.pbenum.dart
guide.pbgrpc.dart
guide.pbjson.dart

服务器端实现
现在我们首先搭建一个gRPC服务器,先引入头文件,然后实现一个servermain函数,在servermain函数中,我们使用grpc.Server.create创建一个server,然后设置监听IP地址和端口,在server中指定调用服务类为RouteGuideService。
dart
import 'package:grpc/grpc.dart' as grpc;
import 'protos/guide.pbgrpc.dart';
servermain() async {
debugPrint('Server start...');
final server = grpc.Server.create(services: [RouteGuideService()]);
await server.serve(
address: '192.168.31.9',
port: 8888,
);
debugPrint('Server listening on port ${server.port}...');
}
在RouteGuideService中实现routeChat方法,远端有访问过来时,就将请求打印出来,同时,将"server message"返回给客户端,实现双向通信。实际上也就是在客户端调用服务端的routeChat函数。
dart
class RouteGuideService extends RouteGuideServiceBase {
@override
Stream<RouteNote> routeChat(
grpc.ServiceCall call, Stream<RouteNote> request) async* {
await for (var note in request) {
debugPrint("get client message: ");
debugPrint(note.message);
yield RouteNote(message: "server message");
}
}
}
客户端实现
现在来实现客户端,引入guide.pbgrpc.dart和grpc/grpc.dart文件,定义全局变量stub用来调用远程函数,创建主函数clientmain,在ClientChannel中设置访问服务器端口和IP,设置 ChannelCredentials.insecure来禁用加密通信,不适用加密证书,加密通信后期再谈论。接着调用RouteGuideClient连接远端服务器,将返回值赋值给stub。最后调用runRouteChat函数,此函数中实现我们数据交互逻辑。
dart
import 'protos/guide.pbgrpc.dart';
import 'package:grpc/grpc.dart';
late RouteGuideClient stub;
clientmain() {
final channel = ClientChannel('192.168.31.9',
port: 8888,
options:
const ChannelOptions(credentials: ChannelCredentials.insecure()));
stub = RouteGuideClient(channel,
options: CallOptions(timeout: const Duration(seconds: 30)));
runRouteChat();
}
在runRouteChat函数中调用stub.routeChat来进行远端函数调用,传入的outgoingNotes函数来向服务端发出申请,返回值call就是服务端返回的信息了。
dart
Future<void> runRouteChat() async {
final call = stub.routeChat(outgoingNotes());
await for (var note in call) {
debugPrint('Got server message:');
debugPrint(note.message);
}
}
outgoingNotes函数实现的功能是,简单的向服务端发送五次信息。
dart
Stream<RouteNote> outgoingNotes() async* {
for (var i = 0; i < 5; i++) {
debugPrint('Sending message to server');
yield RouteNote(message: "client message");
}
}
gRPC连接建立,通信完成
上述配置和代码都完成后,就可以进行gRPC连接,实现全双工通信了,效果图如下:
