是否可以检测原始协议缓冲区消息的类型(在byte [])
我遇到端点可以接收不同消息的情况,我需要能够在反序列化之前检测到类型。
我正在使用protobuf-net
答案 0 :(得分:15)
您不能孤立地检测类型,因为protobuf规范不会为此向流添加任何数据;但是,根据具体情况,有很多方法可以简化这一过程:
在原始TCP流的情况下,最后一种方法实际上非常有价值;这是在线上与union类型相同,但具有不同的实现;通过预先确定1 = Foo,2 = Bar等(与联合类型方法完全相同),您可以使用SerializeWithLengthPrefix
来编写(指定1/2 / etc作为字段编号),以及要读取的非泛型TryDeserializeWithLengthPrefix
(这是在v1 API中的Serializer.NonGeneric下,或者在v2 API中的TypeModel上),您可以提供一个类型映射,将数字解析回类型,因此反序列化正确的类型。并预先解决“为什么这对TCP流有用?” - 因为:在正在进行的TCP流中,您需要使用WithLengthPrefix
方法无论如何,以避免过度阅读流;所以你不妨免费获得类型标识符!
摘要:
答案 1 :(得分:12)
一个典型的选择是让包装器消息充当“选项类型”或区别联合。您可以有一个枚举(每个消息类型一个)和一个包含消息类型的字段的消息,然后是每个消息类型一个可选字段。
这在Protobuf文档中描述为"union type"。
答案 2 :(得分:3)
你可以像这样包装它。数据保存实际信息的地方。
message MyCustomProtocol {
required int32 protocolVersion = 1;
required int32 messageType = 2;
bytes data = 3;
}
协议的一般规则是包含协议版本。一旦有了新老客户,您将非常乐意拥有它。
答案 3 :(得分:1)
您可以使用称为Self Describing Messages的技术。它可以用来生成一组.proto文件,这些文件描述包装器中编码为“ any”的每种消息类型。文档中的示例:
public class MainActivity extends AppCompatActivity implements VideoRendererEventListener {
private static final String TAG = "MainActivity";
private SimpleExoPlayerView simpleExoPlayerView;
private SimpleExoPlayer player;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
LoadControl loadControl = new DefaultLoadControl();
player = ExoPlayerFactory.newSimpleInstance(this, trackSelector, loadControl);
simpleExoPlayerView = new SimpleExoPlayerView(this);
simpleExoPlayerView = findViewById(R.id.player_view);
//Set media controller
simpleExoPlayerView.setUseController(true);
simpleExoPlayerView.requestFocus();
// Bind the player to the view.
simpleExoPlayerView.setPlayer(player);
/// ========================== load file from url
Uri mp4VideoUri = Uri.parse("http://playlist.m3u8");
DefaultBandwidthMeter bandwidthMeterA = new DefaultBandwidthMeter();
//Produces DataSource instances through which media data is loaded.
DefaultDataSourceFactory dataSourceFactory = new DefaultDataSourceFactory(this, Util.getUserAgent(this, "exoplayer2example"), bandwidthMeterA);
//FOR LIVESTREAM LINK:
MediaSource videoSource = new HlsMediaSource(mp4VideoUri, dataSourceFactory, 1, null, null);
final LoopingMediaSource loopingSource = new LoopingMediaSource(videoSource);
// Prepare the player with the source.
player.prepare(loopingSource);
player.addListener(new ExoPlayer.EventListener() {
@Override
public void onTimelineChanged(Timeline timeline, Object manifest) {
Log.v(TAG, "Listener-onTimelineChanged...");
}
@Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
Log.v(TAG, "Listener-onTracksChanged...");
}
@Override
public void onLoadingChanged(boolean isLoading) {
Log.v(TAG, "Listener-onLoadingChanged...isLoading:" + isLoading);
}
@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
Log.v(TAG, "Listener-onPlayerStateChanged..." + playbackState);
}
@Override
public void onRepeatModeChanged(int repeatMode) {
Log.v(TAG, "Listener-onRepeatModeChanged...");
}
@Override
public void onPlayerError(ExoPlaybackException error) {
Log.v(TAG, "Listener-onPlayerError...");
player.stop();
player.prepare(loopingSource);
player.setPlayWhenReady(true);
}
@Override
public void onPositionDiscontinuity() {
Log.v(TAG, "Listener-onPositionDiscontinuity...");
}
@Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
Log.v(TAG, "Listener-onPlaybackParametersChanged...");
}
});
player.setPlayWhenReady(true);
player.setVideoDebugListener(this);
}
@Override
public void onVideoEnabled(DecoderCounters counters) {
}
@Override
public void onVideoDecoderInitialized(String decoderName, long initializedTimestampMs, long initializationDurationMs) {
}
@Override
public void onVideoInputFormatChanged(Format format) {
}
@Override
public void onDroppedFrames(int count, long elapsedMs) {
}
@Override
public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
Log.v(TAG, "onVideoSizeChanged [" + " width: " + width + " height: " + height + "]");
}
@Override
public void onRenderedFirstFrame(Surface surface) {
}
@Override
public void onVideoDisabled(DecoderCounters counters) {
}
@Override
protected void onStop() {
super.onStop();
Log.v(TAG, "onStop()...");
}
@Override
protected void onStart() {
super.onStart();
}
@Override
protected void onResume() {
super.onResume();
Log.v(TAG, "onResume()...");
}
@Override
protected void onPause() {
super.onPause();
Log.v(TAG, "onPause()...");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.v(TAG, "onDestroy()...");
player.release();
}
}
应注意,在编写此响应时,仅对这些消息提供本机支持。