diff --git a/README.md b/README.md index b8ac1db..30dc602 100644 --- a/README.md +++ b/README.md @@ -6,4 +6,6 @@ * 能通讯,有响应数据,还未解析响应数据 ![](docs/plan.png) * 基本信息(5档报价) -![](docs/plan20241025.png) \ No newline at end of file +![](docs/plan20241025.png) +* 基本信息(股票列表) +![](docs/plan20241028.png) \ No newline at end of file diff --git a/client.go b/client.go index 3588599..e8f994f 100644 --- a/client.go +++ b/client.go @@ -19,20 +19,15 @@ func Dial(addr string, op ...client.Option) (cli *Client, err error) { } cli.c, err = dial.TCP(addr, func(c *client.Client) { - c.Logger.WithHEX() //以HEX显示 - c.SetOption(op...) //自定义选项 - //c.AllReader = ios.NewAllReader(c.Reader.(io.Reader), protocol.ReadFrom) //分包 + c.Logger.WithHEX() //以HEX显示 + c.SetOption(op...) //自定义选项 c.Event.OnReadFrom = protocol.ReadFrom //分包 c.Event.OnDealMessage = cli.handlerDealMessage //处理分包数据 - - logs.Debug("option") }) if err != nil { return nil, err } - logs.Debug("run") - logs.Debugf("%#v\n", cli.c.Event.OnReadFrom) go cli.c.Run() err = cli.connect() @@ -62,10 +57,10 @@ func (this *Client) handlerDealMessage(c *client.Client, msg ios.Acker) { var resp any switch f.Type { case protocol.TypeSecurityQuote: - resp = protocol.MSecurityQuote.Decode(f.Data) + resp = protocol.MStockQuote.Decode(f.Data) case protocol.TypeSecurityList: - resp, err = protocol.MSecurityList.Decode(f.Data) + resp, err = protocol.MStockList.Decode(f.Data) } @@ -74,7 +69,6 @@ func (this *Client) handlerDealMessage(c *client.Client, msg ios.Acker) { return } - logs.Debug(resp) this.w.Done(conv.String(f.MsgID), resp) } @@ -112,19 +106,19 @@ func (this *Client) connect() error { } // GetSecurityList 获取市场内指定范围内的所有证券代码 -func (this *Client) GetSecurityList(exchange protocol.Exchange, starts ...uint16) (*protocol.SecurityListResp, error) { - f := protocol.MSecurityList.Frame(exchange, starts...) +func (this *Client) GetSecurityList(exchange protocol.Exchange, starts ...uint16) (*protocol.StockListResp, error) { + f := protocol.MStockList.Frame(exchange, starts...) result, err := this.SendFrame(f) if err != nil { return nil, err } - return result.(*protocol.SecurityListResp), nil + return result.(*protocol.StockListResp), nil } // GetSecurityQuotes 获取盘口五档报价 -func (this *Client) GetSecurityQuotes(m map[protocol.Exchange]string) (protocol.SecurityQuotesResp, error) { - f, err := protocol.MSecurityQuote.Frame(m) +func (this *Client) GetSecurityQuotes(m map[protocol.Exchange]string) (protocol.StockQuotesResp, error) { + f, err := protocol.MStockQuote.Frame(m) if err != nil { return nil, err } @@ -132,5 +126,5 @@ func (this *Client) GetSecurityQuotes(m map[protocol.Exchange]string) (protocol. if err != nil { return nil, err } - return result.(protocol.SecurityQuotesResp), nil + return result.(protocol.StockQuotesResp), nil } diff --git a/docs/plan20241025.png b/docs/plan20241025.png new file mode 100644 index 0000000..60a8325 Binary files /dev/null and b/docs/plan20241025.png differ diff --git a/docs/plan20241028.png b/docs/plan20241028.png new file mode 100644 index 0000000..ece431c Binary files /dev/null and b/docs/plan20241028.png differ diff --git a/example/test/main.go b/example/test/main.go index c4cdd4a..3442d4c 100644 --- a/example/test/main.go +++ b/example/test/main.go @@ -1,12 +1,6 @@ package main import ( - "bytes" - "encoding/binary" - "github.com/injoyai/goutil/g" - "github.com/injoyai/ios/client" - "github.com/injoyai/ios/server" - "github.com/injoyai/ios/server/listen" "github.com/injoyai/logs" "github.com/injoyai/tdx" "github.com/injoyai/tdx/protocol" @@ -40,20 +34,3 @@ func main() { select {} } - -// 监听第三方包发送的数据,确定协议用 -func _listen() { - listen.RunTCP(7709, func(s *server.Server) { - s.SetClientOption(func(c *client.Client) { - c.Logger.WithHEX() - }) - }) - - buf := new(bytes.Buffer) - err := binary.Write(buf, binary.LittleEndian, g.Map{ - "name": "名称", - "age": 17, - }) - logs.PrintErr(err) - logs.Debug(buf.String()) -} diff --git a/example/testlist/main.go b/example/testlist/main.go index f228701..f800a10 100644 --- a/example/testlist/main.go +++ b/example/testlist/main.go @@ -14,7 +14,7 @@ func main() { logs.PrintErr(err) for _, v := range resp.List { - logs.Debugf("%#v\n", v) + logs.Debug(v) } select {} diff --git a/go.mod b/go.mod index f735343..a4f2092 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/injoyai/base v1.0.18 github.com/injoyai/conv v1.1.10 github.com/injoyai/goutil v0.0.0-20241009040015-3d20afe3efe6 - github.com/injoyai/ios v0.0.3 + github.com/injoyai/ios v0.0.4 github.com/injoyai/logs v1.0.9 golang.org/x/text v0.16.0 ) diff --git a/go.sum b/go.sum index 82c531a..821a15f 100644 --- a/go.sum +++ b/go.sum @@ -1068,8 +1068,8 @@ github.com/injoyai/goutil v0.0.0-20241009040015-3d20afe3efe6 h1:ShXZNuV2tQOD9xlz github.com/injoyai/goutil v0.0.0-20241009040015-3d20afe3efe6/go.mod h1:lXrP8bGSoueX7sBniT5pZctp1e2z3cVZYVeRrjQSKoc= github.com/injoyai/io v0.1.8 h1:C+pt2LLUNhCu80EVuzCs6+vetHf6Ny5ANAIOH8QUAco= github.com/injoyai/io v0.1.8/go.mod h1:khts/5VvSJVm8Dl1fp0C+D8L0pmRrXtWsp+SJqlTgpw= -github.com/injoyai/ios v0.0.3 h1:AAwcMbm9/eBNOT1rqdbvwMlZQFxNCyMUfDDQQYTK7m4= -github.com/injoyai/ios v0.0.3/go.mod h1:heABkaIUwoRRe424otl6mKgdU6LYt5gadav/V4gaojA= +github.com/injoyai/ios v0.0.4 h1:yEZ6wN5uCSjAJB4qwpT6R77aMtjkblZo4giKwu9/s7Y= +github.com/injoyai/ios v0.0.4/go.mod h1:heABkaIUwoRRe424otl6mKgdU6LYt5gadav/V4gaojA= github.com/injoyai/logs v1.0.7/go.mod h1:CLchJCGhb39Obyrci816R+KMtbxZhgPs0FuikhyixK4= github.com/injoyai/logs v1.0.9 h1:Wq7rCVIQKcPx+z+lzKQb2qyDK4TML/cgmaSZN9tx33c= github.com/injoyai/logs v1.0.9/go.mod h1:CLchJCGhb39Obyrci816R+KMtbxZhgPs0FuikhyixK4= diff --git a/protocol/frame.go b/protocol/frame.go index 072d10a..448c6ca 100644 --- a/protocol/frame.go +++ b/protocol/frame.go @@ -7,7 +7,6 @@ import ( "github.com/injoyai/base/bytes" "github.com/injoyai/base/g" "github.com/injoyai/conv" - "github.com/injoyai/logs" "io" ) @@ -16,7 +15,7 @@ const ( Prefix = 0x0c // PrefixResp 响应帧头 - PrefixResp = 0xb1cb74 + PrefixResp = 0xb1cb7400 ) type Message interface { @@ -109,7 +108,7 @@ func Decode(bs []byte) (*Response, error) { // ReadFrom 这里的r推荐传入*bufio.Reader func ReadFrom(r io.Reader) (result []byte, err error) { - logs.Debug("ReadFrom") + prefix := make([]byte, 4) for { result = []byte(nil) @@ -133,8 +132,7 @@ func ReadFrom(r io.Reader) (result []byte, err error) { result = append(result, buf...) //获取后续字节长度 - length := uint16(result[11])<<8 + uint16(result[10]) - logs.Debug("长度:", length) + length := uint16(result[13])<<8 + uint16(result[12]) buf = make([]byte, length) _, err = io.ReadFull(r, buf) if err != nil { diff --git a/protocol/frame_test.go b/protocol/frame_test.go index 8ab3379..e67abe8 100644 --- a/protocol/frame_test.go +++ b/protocol/frame_test.go @@ -1,6 +1,7 @@ package protocol import ( + "bytes" "encoding/hex" "testing" ) @@ -59,3 +60,25 @@ func TestDecode(t *testing.T) { // //t.Log(result) } + +func TestReadFrom(t *testing.T) { + s := "b1cb74001c00000000000d005100bd00789c6378c12ec325c7cb2061c5b4898987b9050ed1f90c2db74c1825bd18c1b42890fecff09c81819191f13fc3c9f3bb169f5e7dfefeb5ef57f7199a305009308208e5b32bb6bcbf701487120031c61e1e" + bs, err := hex.DecodeString(s) + if err != nil { + t.Error(err) + return + } + result, err := ReadFrom(bytes.NewReader(bs)) + if err != nil { + t.Error(err) + return + } + t.Log(hex.EncodeToString(result)) + resp, err := Decode(result) + if err != nil { + t.Error(err) + return + } + t.Log(hex.EncodeToString(resp.Data)) + t.Log(string(resp.Data)) +} diff --git a/protocol/model_quote.go b/protocol/model_stock_quote.go similarity index 81% rename from protocol/model_quote.go rename to protocol/model_stock_quote.go index 8e6efd7..625b105 100644 --- a/protocol/model_quote.go +++ b/protocol/model_stock_quote.go @@ -8,9 +8,9 @@ import ( ) var ( - MConnect = connect{} - MSecurityQuote = securityQuote{} - MSecurityList = securityList{} + MConnect = connect{} + MStockQuote = stockQuote{} + MStockList = stockList{} ) type ConnectResp struct { @@ -41,22 +41,26 @@ func (connect) Decode(bs []byte) (*ConnectResp, error) { */ -type SecurityListResp struct { +type StockListResp struct { Count uint16 - List []*Security + List []*Stock } -type Security struct { - Code string - VolUnit uint16 - DecimalPoint int8 - Name string - PreClose float64 +type Stock struct { + Name string //股票名称 + Code string //股票代码 + VolUnit uint16 //未知 + DecimalPoint int8 //未知 + PreClose float64 //未知 } -type securityList struct{} +func (this *Stock) String() string { + return fmt.Sprintf("%s(%s)", this.Name, this.Code) +} -func (securityList) Frame(exchange Exchange, starts ...uint16) *Frame { +type stockList struct{} + +func (stockList) Frame(exchange Exchange, starts ...uint16) *Frame { start := conv.DefaultUint16(0, starts...) return &Frame{ Control: Control01, @@ -65,25 +69,26 @@ func (securityList) Frame(exchange Exchange, starts ...uint16) *Frame { } } -func (securityList) Decode(bs []byte) (*SecurityListResp, error) { +func (stockList) Decode(bs []byte) (*StockListResp, error) { if len(bs) < 2 { return nil, errors.New("数据长度不足") } - resp := &SecurityListResp{ + resp := &StockListResp{ Count: Uint16(bs[:2]), } bs = bs[2:] for i := uint16(0); i < resp.Count; i++ { - sec := &Security{ - Code: String(bs[:6]), - VolUnit: Uint16(bs[6:8]), - Name: string(UTF8ToGBK(bs[8:16])), - PreClose: getVolume(Uint32(bs[16:20])), + sec := &Stock{ + Code: string(bs[:6]), + VolUnit: Uint16(bs[6:8]), + Name: string(UTF8ToGBK(bs[8:16])), + DecimalPoint: int8(bs[20]), + PreClose: getVolume(Uint32(bs[21:25])), } - bs = bs[20:] + bs = bs[29:] resp.List = append(resp.List, sec) } @@ -97,9 +102,9 @@ func (securityList) Decode(bs []byte) (*SecurityListResp, error) { */ -type SecurityQuotesResp []*SecurityQuote +type StockQuotesResp []*StockQuote -func (this SecurityQuotesResp) String() string { +func (this StockQuotesResp) String() string { ls := []string(nil) for _, v := range this { ls = append(ls, v.String()) @@ -107,7 +112,7 @@ func (this SecurityQuotesResp) String() string { return strings.Join(ls, "\n") } -type SecurityQuote struct { +type StockQuote struct { Exchange Exchange // 市场 Code string // 股票代码 6个ascii字符串 Active1 uint16 // 活跃度 @@ -136,7 +141,7 @@ type SecurityQuote struct { Active2 uint16 // 活跃度 } -func (this *SecurityQuote) String() string { +func (this *StockQuote) String() string { return fmt.Sprintf(`%s%s %s 总量:%s, 现量:%s, 总金额:%s, 内盘:%s, 外盘:%s @@ -149,9 +154,9 @@ func (this *SecurityQuote) String() string { ) } -type securityQuote struct{} +type stockQuote struct{} -func (this securityQuote) Frame(m map[Exchange]string) (*Frame, error) { +func (this stockQuote) Frame(m map[Exchange]string) (*Frame, error) { f := &Frame{ Control: Control01, Type: TypeSecurityQuote, @@ -196,11 +201,11 @@ b212 昨天收盘价1186 8defd10c 服务时间 c005bed2668e05be15804d8ba12cb3b13a0083c3034100badc029d014201bc990384f70443029da503b7af074403a6e501b9db044504a6e2028dd5048d050000000000005909 */ -func (this securityQuote) Decode(bs []byte) SecurityQuotesResp { +func (this stockQuote) Decode(bs []byte) StockQuotesResp { //logs.Debug(hex.EncodeToString(bs)) - resp := SecurityQuotesResp{} + resp := StockQuotesResp{} //前2字节是什么? bs = bs[2:] @@ -209,7 +214,7 @@ func (this securityQuote) Decode(bs []byte) SecurityQuotesResp { bs = bs[2:] for i := uint16(0); i < number; i++ { - sec := &SecurityQuote{ + sec := &StockQuote{ Exchange: Exchange(bs[0]), Code: string(UTF8ToGBK(bs[1:7])), Active1: Uint16(bs[7:9]), diff --git a/protocol/model_quote_test.go b/protocol/model_stock_quote_test.go similarity index 93% rename from protocol/model_quote_test.go rename to protocol/model_stock_quote_test.go index ec0fc1c..5b5517c 100644 --- a/protocol/model_quote_test.go +++ b/protocol/model_stock_quote_test.go @@ -10,7 +10,7 @@ import ( 0c02000000011a001a003e05050000000000000002000030303030303101363030303038 */ func TestNewSecurityQuotes(t *testing.T) { - f, err := MSecurityQuote.Frame(map[Exchange]string{ + f, err := MStockQuote.Frame(map[Exchange]string{ ExchangeSH: "000001", ExchangeSZ: "600008", }) @@ -48,6 +48,6 @@ func Test_getPrice(t *testing.T) { 0c020000000106000600500400000000 */ func Test_securityList_Frame(t *testing.T) { - f := MSecurityList.Frame(ExchangeSH, 0) + f := MStockList.Frame(ExchangeSH, 0) t.Log(f.Bytes().HEX()) } diff --git a/protocol/unit.go b/protocol/unit.go index f5a40f3..3afa680 100644 --- a/protocol/unit.go +++ b/protocol/unit.go @@ -10,18 +10,22 @@ import ( "io" ) +// String 字节先转小端,再转字符 func String(bs []byte) string { return string(bytes2.Reverse(bs)) } +// Bytes 任意类型转小端字节 func Bytes(n any) []byte { return bytes2.Reverse(conv.Bytes(n)) } +// Uint32 字节通过小端方式转为uint32 func Uint32(bs []byte) uint32 { return conv.Uint32(bytes2.Reverse(bs)) } +// Uint16 字节通过小端方式转为uint16 func Uint16(bs []byte) uint16 { return conv.Uint16(bytes2.Reverse(bs)) }