Giter Site home page Giter Site logo

goframe's Introduction

goframe

goframe provides wrapped net.Conn that can send and receive framed data.

License GoDoc travis Go Report Card

wrapped conn interface

goframe contains one FrameConn interface and some concrete FrameConn implementations:

type FrameConn interface {
	ReadFrame() ([]byte, error)
	WriteFrame(p []byte) error
	Close() error
	Conn() net.Conn
}

You can use NewXXXXXXX function to get a concrete FrameConn.

When you want to send a frame, you use WriteFrame. When you want to receve a frame, you use ReadFrame.

examples

Currently I have implemented some FrameConns that has same formats to Netty frame decoders and encoders. So we can use Go and popular netty framework to communicate. I have created some examples to demonstrate it.

Those examples contains client and server for both go and netty, so you can use any client and any server to start.

concrete FrameConn implementations

  1. FixedLengthFrameConn: each frame has fixed number of bytes. ReadFrame returns the fixed length bytes and WriteFrame can write n * fixed length bytes.
  2. LineBasedFrameConn: split data with line separator (\n or \r\n). WriteFrame writes data p and appends "\r\n"
  3. DelimiterBasedFrameConn: split data with a specific delimiter.
  4. lengthFieldBasedFrameConn: it is a complex FrameConn. It contains several parameters and can produce many frame format. I has copy descriptions from Netty javadoc:

Here are some decoder example that will give you the basic idea on which option does what.

2 bytes length field at offset 0, do not strip header

The value of the length field in this example is 12 (0x0C) which represents the length of "HELLO, WORLD". By default, the decoder assumes that the length field represents the number of the bytes that follows the length field. Therefore, it can be decoded with the simplistic parameter combination.

 lengthFieldOffset   = 0
 lengthFieldLength   = 2
 lengthAdjustment    = 0
 initialBytesToStrip = 0 (= do not strip header)


 BEFORE DECODE (14 bytes)         AFTER DECODE (14 bytes)
 +--------+----------------+      +--------+----------------+
 | Length | Actual Content |----->| Length | Actual Content |
 | 0x000C | "HELLO, WORLD" |      | 0x000C | "HELLO, WORLD" |
 +--------+----------------+      +--------+----------------+

2 bytes length field at offset 0, strip header

Because we can get the length of the content by calling ByteBuf.readableBytes(), you might want to strip the length field by specifying initialBytesToStrip. In this example, we specified 2, that is same with the length of the length field, to strip the first two bytes.

 lengthFieldOffset   = 0
 lengthFieldLength   = 2
 lengthAdjustment    = 0
 initialBytesToStrip = 2 (= the length of the Length field)

 BEFORE DECODE (14 bytes)         AFTER DECODE (12 bytes)
 +--------+----------------+      +----------------+
 | Length | Actual Content |----->| Actual Content |
 | 0x000C | "HELLO, WORLD" |      | "HELLO, WORLD" |
 +--------+----------------+      +----------------+

2 bytes length field at offset 0, do not strip header, the length field represents the length of the whole message

In most cases, the length field represents the length of the message body only, as shown in the previous examples. However, in some protocols, the length field represents the length of the whole message, including the message header. In such a case, we specify a non-zero lengthAdjustment. Because the length value in this example message is always greater than the body length by 2, we specify -2 as lengthAdjustment for compensation.

 lengthFieldOffset   =  0
 lengthFieldLength   =  2
 lengthAdjustment    = -2 (= the length of the Length field)
 initialBytesToStrip =  0

 BEFORE DECODE (14 bytes)         AFTER DECODE (14 bytes)
 +--------+----------------+      +--------+----------------+
 | Length | Actual Content |----->| Length | Actual Content |
 | 0x000E | "HELLO, WORLD" |      | 0x000E | "HELLO, WORLD" |
 +--------+----------------+      +--------+----------------+

3 bytes length field at the end of 5 bytes header, do not strip header

The following message is a simple variation of the first example. An extra header value is prepended to the message. lengthAdjustment is zero again because the decoder always takes the length of the prepended data into account during frame length calculation.

 lengthFieldOffset   = 2 (= the length of Header 1)
 lengthFieldLength   = 3
 lengthAdjustment    = 0
 initialBytesToStrip = 0

 BEFORE DECODE (17 bytes)                      AFTER DECODE (17 bytes)
 +----------+----------+----------------+      +----------+----------+----------------+
 | Header 1 |  Length  | Actual Content |----->| Header 1 |  Length  | Actual Content |
 |  0xCAFE  | 0x00000C | "HELLO, WORLD" |      |  0xCAFE  | 0x00000C | "HELLO, WORLD" |
 +----------+----------+----------------+      +----------+----------+----------------+

3 bytes length field at the beginning of 5 bytes header, do not strip header

This is an advanced example that shows the case where there is an extra header between the length field and the message body. You have to specify a positive lengthAdjustment so that the decoder counts the extra header into the frame length calculation.

 lengthFieldOffset   = 0
 lengthFieldLength   = 3
 lengthAdjustment    = 2 (= the length of Header 1)
 initialBytesToStrip = 0

 BEFORE DECODE (17 bytes)                      AFTER DECODE (17 bytes)
 +----------+----------+----------------+      +----------+----------+----------------+
 |  Length  | Header 1 | Actual Content |----->|  Length  | Header 1 | Actual Content |
 | 0x00000C |  0xCAFE  | "HELLO, WORLD" |      | 0x00000C |  0xCAFE  | "HELLO, WORLD" |
 +----------+----------+----------------+      +----------+----------+----------------+

2 bytes length field at offset 1 in the middle of 4 bytes header, strip the first header field and the length field

This is a combination of all the examples above. There are the prepended header before the length field and the extra header after the length field. The prepended header affects the lengthFieldOffset and the extra header affects the lengthAdjustment. We also specified a non-zero initialBytesToStrip to strip the length field and the prepended header from the frame. If you don't want to strip the prepended header, you could specify 0 for initialBytesToSkip.

 lengthFieldOffset   = 1 (= the length of HDR1)
 lengthFieldLength   = 2
 lengthAdjustment    = 1 (= the length of HDR2)
 initialBytesToStrip = 3 (= the length of HDR1 + LEN)

 BEFORE DECODE (16 bytes)                       AFTER DECODE (13 bytes)
 +------+--------+------+----------------+      +------+----------------+
 | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content |
 | 0xCA | 0x000C | 0xFE | "HELLO, WORLD" |      | 0xFE | "HELLO, WORLD" |
 +------+--------+------+----------------+      +------+----------------+

2 bytes length field at offset 1 in the middle of 4 bytes header, strip the first header field and the length field, the length field represents the length of the whole message

Let's give another twist to the previous example. The only difference from the previous example is that the length field represents the length of the whole message instead of the message body, just like the third example. We have to count the length of HDR1 and Length into lengthAdjustment. Please note that we don't need to take the length of HDR2 into account because the length field already includes the whole header length.

 lengthFieldOffset   =  1
 lengthFieldLength   =  2
 lengthAdjustment    = -3 (= the length of HDR1 + LEN, negative)
 initialBytesToStrip =  3

 BEFORE DECODE (16 bytes)                       AFTER DECODE (13 bytes)
 +------+--------+------+----------------+      +------+----------------+
 | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content |
 | 0xCA | 0x0010 | 0xFE | "HELLO, WORLD" |      | 0xFE | "HELLO, WORLD" |
 +------+--------+------+----------------+      +------+----------------+

For encoder, it prepends the length of the message. The length value is prepended as a binary form. For example, LengthFieldLength(2) will encode the following 12-bytes string:

 +----------------+
 | "HELLO, WORLD" |
 +----------------+

into the following:

 +--------+----------------+
 + 0x000C | "HELLO, WORLD" |
 +--------+----------------+

If you turned on the lengthIncludesLengthFieldLength flag in the EncoderConfig, the encoded data would look like the following (12 (original data) + 2 (prepended data) = 14 (0xE)):

 +--------+----------------+
 + 0x000E | "HELLO, WORLD" |
 +--------+----------------+

goframe's People

Contributors

amasses avatar firedtoad avatar panjf2000 avatar smallnest avatar supermario1990 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

goframe's Issues

如何确认使用某个类型的编解码器

我发现我现在的消息满足
3 bytes length field at the beginning of 5 bytes header, do not strip header
这个格式,但是不知道要用哪一个编解码器
希望可以得到解答

参数配置和期望结果不一样,劳烦请教一下。

[]byte{  0xFF,0xFF, //固定头1
	0x09,//长度 = 序列号域 + 命令代码 + 数据域 +校验和域 (不包含 固定头1 固定头2)
	0x80,//固定头2 
	0x31,//序列号域
	0x32,//命令代码
	0x33,0x34,0x35,0x36,0x37,0x38,//数据域
	0xFA,//校验和域
}

使用

	decoderConfig := goframe.DecoderConfig{
		ByteOrder:           binary.BigEndian,
		LengthFieldOffset:   2, //起始域
		LengthFieldLength:   1, //长度域
		LengthAdjustment:    0 , //版本
		InitialBytesToStrip: 3, // 起始域 + 长度域
	}

期望值

0x31,//序列号域
0x32,//命令代码
0x33,0x34,0x35,0x36,0x37,0x38,//数据域
0xFA,//校验和域

实际解析出来

---------------------------------------------
003132333435
---------------------------------------------
3738FAFFFF09003132333435363738FAFFFF09003132333435363738FAFFFF09003132333435363738FAFFFF09003132333435
---------------------------------------------
3738FAFFFF09003132333435363738FAFFFF09003132333435363738FAFFFF09003132333435363738FAFFFF09003132333435
---------------------------------------------
3738FAFFFF09003132333435363738FAFFFF09003132333435363738FAFFFF09003132333435363738FA333435363738FAFFFF
---------------------------------------------
003132333435
---------------------------------------------
3738FAFFFF09003132333435363738FAFFFF09003132333435363738FAFFFF09003132333435363738FAFFFF09003132333435
---------------------------------------------
3738FAFFFF09003132333435363738FAFFFF09003132333435363738FAFFFF09003132333435363738FAFFFF09003132333435

请问该如何配置 ,谢谢您!

关于LengthFieldBasedFrame的困惑

我把example中的例子改成下面这样为啥就跑不通了呢?希望鸟哥解惑下

encoderConfig := goframe.EncoderConfig{
		ByteOrder:                       binary.BigEndian,
		LengthFieldLength:               2,
		LengthAdjustment:                -2,
		LengthIncludesLengthFieldLength: false,
	}

	decoderConfig := goframe.DecoderConfig{
		ByteOrder:           binary.BigEndian,
		LengthFieldOffset:   0,
		LengthFieldLength:   2,
		LengthAdjustment:    -2,
		InitialBytesToStrip: 0,
	}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.