This repository has been archived by the owner on Jul 16, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 167
RSocket Binary
Libing Chen edited this page May 28, 2023
·
5 revisions
在很多的情况下,我们会在网络上传输二进制数据,如用户的照片、头像、合同文件等等,这个时候我们就需要传输二进制数据。 在实际的业务中,我们如何设计这样的接口?
将二进制数据组装为字节数组,然后作为参数传输给服务方,服务接口如下:
public interface UserService {
Mono<Void> updateAvatar(Integer userId, byte[] avatar);
}
但是这种方式非常浪费系统资源,涉及到各种内存copy操作,从input stream读取,然后转换为byte数组,然后再copy到堆外内存写到网络。当然这个过程还有对象序列化的操作,又是一堆内存copy。 总之,这种方式可以工作,但是绝对不是高效的方式。 如果是视频流媒体等,这个接口几乎无法工作。
首先我们不屏蔽技术,RSocket Java是基于Netty的,为了更好方便传输二进制数据,我们直接使用ByteBuf和ByteBuffer这两个接口传输byte数据流。看一下如下代码结构:
public interface UserService {
default Mono<Void> updateAvatar(Integer id, ByteBuffer avatar) {
CompositeByteBuf byteBuf = PooledByteBufAllocator.DEFAULT.compositeDirectBuffer(2, toByteBuf(id), toByteBuf(avatar));
return updateAvatar(byteBuf);
}
Mono<Void> updateAvatar(ByteBuf byteBuf);
}
考虑到API的友好性,我们使用Java接口的default method提供给应用进行调用,如你看到的updateAvatar,还是非常容易理解的业务接口。 接下来我们在default method中稍微做一些代码处理, 将参数转换为Netty的ByteBuf,然后交给负责通讯的通讯接口。
而在服务端,我们只需调用ByteBuf的接口,读取相关的数据,然后进行逻辑处理就可以啦,逻辑也非常简单。当然考虑到实际的便捷性,你可以使用一些工具类来简化你的工作。
Mono<Void> updateAvatar(ByteBuf byteBuf) {
int userId = byteBuf.readInt();
ByteBuf avatar = byteBuf.slice();
....
}
如果ByteBuf作为返回值类型,这里主要有两个场景:
- 第一种是用于告知RSocket SDK不要进行反序列化,因为我接下来要进行其他输出,如REST API输出
//接口声明
Mono<ByteBuffer> findById(Integer id);
//服务端实现
Mono<User> findById(Integer id);
- 第二种是真的二进制,开发者要自行进行ByteBuf内容解析,至于如何解析,是服务实现方开发者自行决定的,如下:
public interface UserServiceExtra {
@ServiceMapping(decoding = "application/json")
Mono<ByteBuffer> findById(Integer id);
}
- Binary: byte stream
- Async message
- Multi transports
- Reactive Semantics
- request/response
- request/stream
- fire-and-forget
- channel
- TCP+TLS
- WebSocket+TLS
- UDP(Aeron)
- RDMA