This is an automated email from the ASF dual-hosted git repository.

wuxinfan pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/dubbo-go.git


The following commit(s) were added to refs/heads/develop by this push:
     new d27f5e743 refactor: add triple protocol config and option (#2900)
d27f5e743 is described below

commit d27f5e743af49b8eacb5e00ecc4628f85977441e
Author: marsevilspirit <[email protected]>
AuthorDate: Sun Jun 8 20:47:41 2025 +0800

    refactor: add triple protocol config and option (#2900)
    
    * fix typo
    
    * add triple options and configs on server and client side
    
    * rename Methods to MethodsConfig
    
    * add remove keepAlive interval and timeout todo
    
    * change type to time.Duration
    
    * change dubbo3 invoker
    
    * refactor protocol options and run success
    
    * add some server protocol option
    
    * add more protocol options
    
    * add protocol and protocol client config clone function
    
    * fix triple option bugs
    
    * add some constant
    
    * add dubbo withProtocol
    
    * fix dubbo.WithProtocol bugs
    
    * add some todo
    
    * add triple maxServerSendMsgSize option and maxServerRecvMsgSize option
    
    * remove tirple config test field
    
    * add some comments
    
    * fix golangci-lint error
    
    * add some comment
    
    * refactor protocol options
    
    * fix integrate_test compatibility/config-api/rpc/triple error
    
    * optimize genKeepAlive options for client
    
    * add some comment
    
    * delete some useless log and add some protocol options
    
    * add useless default tag
    
    * compat config package
    
    * rename protocol_client file
    
    * fix typo
    
    * fix comments
    
    * fix go test error
---
 client/action.go                                   |   9 +-
 client/options.go                                  |  34 ++-
 client/options_test.go                             |   4 +-
 common/constant/default.go                         |   3 +
 common/constant/key.go                             |   8 +-
 compat.go                                          |  30 ++-
 config/protocol_config.go                          |   2 +
 config/root_config.go                              |   2 +-
 .../triple/options.go => config/triple_config.go   |  34 +--
 .../options.go => global/protocol_client_config.go |  40 +--
 global/protocol_config.go                          |  24 +-
 global/reference_config.go                         | 115 +++++----
 global/triple_config.go                            |  47 ++++
 metadata/metadata_service_test.go                  |   6 +-
 options.go                                         |  23 +-
 protocol/options.go                                | 283 +++++++++++++++++----
 protocol/triple/client.go                          |  75 ++++--
 protocol/triple/dubbo3_invoker.go                  |  12 +
 protocol/triple/options.go                         |  70 ++++-
 protocol/triple/server.go                          |  47 +++-
 protocol/triple/triple.go                          |  11 +-
 registry/polaris/service_discovery.go              |   2 +-
 server/action.go                                   |   6 +
 server/options.go                                  |   8 +-
 24 files changed, 676 insertions(+), 219 deletions(-)

diff --git a/client/action.go b/client/action.go
index 4c437c42d..91eda4eb2 100644
--- a/client/action.go
+++ b/client/action.go
@@ -132,9 +132,16 @@ func (refOpts *ReferenceOptions) refer(srv 
common.RPCService, info *ClientInfo)
                common.WithParamsValue(constant.BeanNameKey, refOpts.id),
                common.WithParamsValue(constant.MetadataTypeKey, 
refOpts.metaDataType),
                common.WithParamsValue(constant.TimeoutKey, 
refOpts.Consumer.RequestTimeout),
+
+               // TODO: Deprecated:use TripleConfig
+               // remove KeepAliveInterval and KeepAliveInterval in version 
4.0.0
                common.WithParamsValue(constant.KeepAliveInterval, 
ref.KeepAliveInterval),
                common.WithParamsValue(constant.KeepAliveTimeout, 
ref.KeepAliveTimeout),
+
+               // attribute
+               common.WithAttribute(constant.TripleConfigKey, 
ref.ProtocolClientConfig.TripleConfig),
                common.WithAttribute(constant.TLSConfigKey, refOpts.TLS),
+
                // for new triple non-IDL mode
                // TODO: remove ISIDL after old triple removed
                common.WithParamsValue(constant.IDLMode, ref.IDLMode),
@@ -389,7 +396,7 @@ func (refOpts *ReferenceOptions) getURLMap() url.Values {
        }
        urlMap.Set(constant.ReferenceFilterKey, 
commonCfg.MergeValue(ref.Filter, "", defaultReferenceFilter))
 
-       for _, v := range ref.Methods {
+       for _, v := range ref.MethodsConfig {
                urlMap.Set("methods."+v.Name+"."+constant.LoadbalanceKey, 
v.LoadBalance)
                urlMap.Set("methods."+v.Name+"."+constant.RetriesKey, v.Retries)
                urlMap.Set("methods."+v.Name+"."+constant.StickyKey, 
strconv.FormatBool(v.Sticky))
diff --git a/client/options.go b/client/options.go
index cdc389cc3..f17e49dc4 100644
--- a/client/options.go
+++ b/client/options.go
@@ -33,6 +33,7 @@ import (
        "dubbo.apache.org/dubbo-go/v3/config"
        "dubbo.apache.org/dubbo-go/v3/global"
        "dubbo.apache.org/dubbo-go/v3/graceful_shutdown"
+       "dubbo.apache.org/dubbo-go/v3/protocol"
        "dubbo.apache.org/dubbo-go/v3/protocol/base"
        "dubbo.apache.org/dubbo-go/v3/proxy"
        "dubbo.apache.org/dubbo-go/v3/registry"
@@ -89,7 +90,7 @@ func (refOpts *ReferenceOptions) init(opts 
...ReferenceOption) error {
        }
 
        // init method
-       methods := refConf.Methods
+       methods := refConf.MethodsConfig
        if length := len(methods); length > 0 {
                refOpts.methodsCompat = make([]*config.MethodConfig, length)
                for i, method := range methods {
@@ -347,7 +348,7 @@ func WithIDL(IDLMode string) ReferenceOption {
 
 func WithProtocolDubbo() ReferenceOption {
        return func(opts *ReferenceOptions) {
-               opts.Reference.Protocol = constant.Dubbo
+               opts.Reference.Protocol = constant.DubboProtocol
        }
 }
 
@@ -359,7 +360,7 @@ func WithProtocolTriple() ReferenceOption {
 
 func WithProtocolJsonRPC() ReferenceOption {
        return func(opts *ReferenceOptions) {
-               opts.Reference.Protocol = "jsonrpc"
+               opts.Reference.Protocol = constant.JSONRPCProtocol
        }
 }
 
@@ -391,10 +392,10 @@ func WithMethod(opts ...config.MethodOption) 
ReferenceOption {
        regOpts := config.NewMethodOptions(opts...)
 
        return func(opts *ReferenceOptions) {
-               if len(opts.Reference.Methods) == 0 {
-                       opts.Reference.Methods = make([]*global.MethodConfig, 0)
+               if len(opts.Reference.MethodsConfig) == 0 {
+                       opts.Reference.MethodsConfig = 
make([]*global.MethodConfig, 0)
                }
-               opts.Reference.Methods = append(opts.Reference.Methods, 
regOpts.Method)
+               opts.Reference.MethodsConfig = 
append(opts.Reference.MethodsConfig, regOpts.Method)
        }
 }
 
@@ -667,6 +668,9 @@ func WithClientClusterStrategy(strategy string) 
ClientOption {
        }
 }
 
+// Deprecated:use triple.WithKeepAliveInterval()
+// TODO: remove KeepAliveInterval and KeepAliveInterval in version 4.0.0
+//
 // If there is no other traffic on the connection, the ping will be sent, only 
works for 'tri' protocol with http2.
 // A minimum value of 10s will be used instead to invoid 'too many pings'.If 
not set, default value is 10s.
 func WithKeepAliveInterval(keepAliveInterval time.Duration) ClientOption {
@@ -678,6 +682,9 @@ func WithKeepAliveInterval(keepAliveInterval time.Duration) 
ClientOption {
        }
 }
 
+// Deprecated:use triple.WithKeepAliveTimeout()
+// TODO: remove KeepAliveInterval and KeepAliveInterval in version 4.0.0
+//
 // WithKeepAliveTimeout is timeout after which the connection will be closed, 
only works for 'tri' protocol with http2
 // If not set, default value is 20s.
 func WithKeepAliveTimeout(keepAliveTimeout time.Duration) ClientOption {
@@ -808,7 +815,7 @@ func WithClientSticky() ClientOption {
 
 func WithClientProtocolDubbo() ClientOption {
        return func(opts *ClientOptions) {
-               opts.Consumer.Protocol = constant.Dubbo
+               opts.Consumer.Protocol = constant.DubboProtocol
        }
 }
 
@@ -820,13 +827,18 @@ func WithClientProtocolTriple() ClientOption {
 
 func WithClientProtocolJsonRPC() ClientOption {
        return func(opts *ClientOptions) {
-               opts.Consumer.Protocol = "jsonrpc"
+               opts.Consumer.Protocol = constant.JSONRPCProtocol
        }
 }
 
-func WithClientProtocol(protocol string) ClientOption {
-       return func(opts *ClientOptions) {
-               opts.Consumer.Protocol = protocol
+func WithClientProtocol(opts ...protocol.ClientOption) ClientOption {
+       proOpts := protocol.NewClientOptions(opts...)
+
+       return func(srvOpts *ClientOptions) {
+               if srvOpts.overallReference.ProtocolClientConfig == nil {
+                       srvOpts.overallReference.ProtocolClientConfig = 
new(global.ProtocolClientConfig)
+               }
+               srvOpts.overallReference.ProtocolClientConfig = 
proOpts.ProtocolClient
        }
 }
 
diff --git a/client/options_test.go b/client/options_test.go
index 8b4ac24f5..1e580db7e 100644
--- a/client/options_test.go
+++ b/client/options_test.go
@@ -578,7 +578,7 @@ func TestWithClientProtocol(t *testing.T) {
                        },
                        verify: func(t *testing.T, cli *Client, err error) {
                                assert.Nil(t, err)
-                               assert.Equal(t, constant.Dubbo, 
cli.cliOpts.Consumer.Protocol)
+                               assert.Equal(t, constant.DubboProtocol, 
cli.cliOpts.Consumer.Protocol)
                        },
                },
                {
@@ -1119,7 +1119,7 @@ func TestWithProtocol(t *testing.T) {
                        },
                        verify: func(t *testing.T, refOpts *ReferenceOptions, 
err error) {
                                assert.Nil(t, err)
-                               assert.Equal(t, constant.Dubbo, 
refOpts.Reference.Protocol)
+                               assert.Equal(t, constant.DubboProtocol, 
refOpts.Reference.Protocol)
                        },
                },
                {
diff --git a/common/constant/default.go b/common/constant/default.go
index 2b8769d84..83480c006 100644
--- a/common/constant/default.go
+++ b/common/constant/default.go
@@ -28,7 +28,10 @@ const (
        OverrideProtocol = "override" //compatible with 2.6.x
        EmptyProtocol    = "empty"
        RouterProtocol   = "router"
+       DubboProtocol    = "dubbo"
        TriProtocol      = "tri"
+       JSONRPCProtocol  = "jsonrpc"
+       RESTProtocol     = "rest"
 )
 
 const (
diff --git a/common/constant/key.go b/common/constant/key.go
index 2694d25fa..828008457 100644
--- a/common/constant/key.go
+++ b/common/constant/key.go
@@ -62,11 +62,15 @@ const (
        MaxServerSendMsgSize   = "max-server-send-msg-size"
        MaxCallRecvMsgSize     = "max-call-recv-msg-size"
        MaxServerRecvMsgSize   = "max-server-recv-msg-size"
-       KeepAliveInterval      = "keep-alive-interval"
-       KeepAliveTimeout       = "keep-alive-timeout"
+
+       // TODO: remove KeepAliveInterval and KeepAliveInterval in version 4.0.0
+       KeepAliveInterval = "keep-alive-interval"
+       KeepAliveTimeout  = "keep-alive-timeout"
 
        // TODO: remove IDLMode after old triple removed
        IDLMode = "IDL-mode"
+
+       TripleConfigKey = "triple-config"
 )
 
 // TODO: remove this after old triple removed
diff --git a/compat.go b/compat.go
index ef31c2350..5c622c369 100644
--- a/compat.go
+++ b/compat.go
@@ -87,6 +87,20 @@ func compatProtocolConfig(c *global.ProtocolConfig) 
*config.ProtocolConfig {
                Ip:                   c.Ip,
                Port:                 c.Port,
                Params:               c.Params,
+               TripleConfig:         compatTripleConfig(c.TripleConfig),
+               MaxServerSendMsgSize: c.MaxServerSendMsgSize,
+               MaxServerRecvMsgSize: c.MaxServerRecvMsgSize,
+       }
+}
+
+// just for compat
+func compatTripleConfig(c *global.TripleConfig) *config.TripleConfig {
+       if c == nil {
+               return nil
+       }
+       return &config.TripleConfig{
+               KeepAliveInterval:    c.KeepAliveInterval,
+               KeepAliveTimeout:     c.KeepAliveTimeout,
                MaxServerSendMsgSize: c.MaxServerSendMsgSize,
                MaxServerRecvMsgSize: c.MaxServerRecvMsgSize,
        }
@@ -444,6 +458,20 @@ func compatGlobalProtocolConfig(c *config.ProtocolConfig) 
*global.ProtocolConfig
                Ip:                   c.Ip,
                Port:                 c.Port,
                Params:               c.Params,
+               TripleConfig:         compatGlobalTripleConfig(c.TripleConfig),
+               MaxServerSendMsgSize: c.MaxServerSendMsgSize,
+               MaxServerRecvMsgSize: c.MaxServerRecvMsgSize,
+       }
+}
+
+// just for compat
+func compatGlobalTripleConfig(c *config.TripleConfig) *global.TripleConfig {
+       if c == nil {
+               return nil
+       }
+       return &global.TripleConfig{
+               KeepAliveInterval:    c.KeepAliveInterval,
+               KeepAliveTimeout:     c.KeepAliveTimeout,
                MaxServerSendMsgSize: c.MaxServerSendMsgSize,
                MaxServerRecvMsgSize: c.MaxServerRecvMsgSize,
        }
@@ -659,7 +687,7 @@ func compatGlobalReferences(c 
map[string]*config.ReferenceConfig) map[string]*gl
                        Version:          ref.Version,
                        Serialization:    ref.Serialization,
                        ProvidedBy:       ref.ProvidedBy,
-                       Methods:          compatGlobalMethod(ref.Methods),
+                       MethodsConfig:    compatGlobalMethod(ref.Methods),
                        Async:            ref.Async,
                        Params:           ref.Params,
                        Generic:          ref.Generic,
diff --git a/config/protocol_config.go b/config/protocol_config.go
index d0b7a7975..f75a1c849 100644
--- a/config/protocol_config.go
+++ b/config/protocol_config.go
@@ -32,6 +32,8 @@ type ProtocolConfig struct {
        Port   string `default:"50051" yaml:"port" json:"port,omitempty" 
property:"port"`
        Params any    `yaml:"params" json:"params,omitempty" property:"params"`
 
+       TripleConfig *TripleConfig `yaml:"triple" json:"triple,omitempty" 
property:"triple"`
+
        // MaxServerSendMsgSize max size of server send message, 
1mb=1000kb=1000000b 1mib=1024kb=1048576b.
        // more detail to see 
https://pkg.go.dev/github.com/dustin/go-humanize#pkg-constants
        MaxServerSendMsgSize string `yaml:"max-server-send-msg-size" 
json:"max-server-send-msg-size,omitempty"`
diff --git a/config/root_config.go b/config/root_config.go
index 94cf48ccd..18934826e 100644
--- a/config/root_config.go
+++ b/config/root_config.go
@@ -69,7 +69,7 @@ func SetRootConfig(r RootConfig) {
 
 // Prefix dubbo
 func (rc *RootConfig) Prefix() string {
-       return constant.Dubbo
+       return constant.DubboProtocol
 }
 
 func GetRootConfig() *RootConfig {
diff --git a/protocol/triple/options.go b/config/triple_config.go
similarity index 52%
copy from protocol/triple/options.go
copy to config/triple_config.go
index 239de2333..2fbd99909 100644
--- a/protocol/triple/options.go
+++ b/config/triple_config.go
@@ -15,32 +15,14 @@
  * limitations under the License.
  */
 
-package triple
+package config
 
-type ServerOptions struct {
-}
-
-func defaultServerOptions() *ServerOptions {
-       return &ServerOptions{}
-}
-
-func NewServerOptions(opts ...ServerOption) *ServerOptions {
-       defSrvOpts := defaultServerOptions()
-       for _, opt := range opts {
-               opt(defSrvOpts)
-       }
-       return defSrvOpts
-}
-
-func (srvOpts *ServerOptions) init(opts ...ServerOption) {
-       for _, opt := range opts {
-               opt(srvOpts)
-       }
-}
-
-type ServerOption func(*ServerOptions)
+type TripleConfig struct {
+       KeepAliveInterval string `yaml:"keep-alive-interval" 
json:"keep-alive-interval,omitempty" property:"keep-alive-interval"`
+       KeepAliveTimeout  string `yaml:"keep-alive-timeout" 
json:"keep-alive-timeout,omitempty" property:"keep-alive-timeout"`
 
-func WithServerEmtryOption() ServerOption {
-       return func(opts *ServerOptions) {
-       }
+       // MaxServerSendMsgSize max size of server send message, 
1mb=1000kb=1000000b 1mib=1024kb=1048576b.
+       // more detail to see 
https://pkg.go.dev/github.com/dustin/go-humanize#pkg-constants
+       MaxServerSendMsgSize string `yaml:"max-server-send-msg-size" 
json:"max-server-send-msg-size,omitempty"` // MaxServerRecvMsgSize max size of 
server receive message
+       MaxServerRecvMsgSize string `yaml:"max-server-recv-msg-size" 
json:"max-server-recv-msg-size,omitempty"`
 }
diff --git a/protocol/triple/options.go b/global/protocol_client_config.go
similarity index 50%
copy from protocol/triple/options.go
copy to global/protocol_client_config.go
index 239de2333..6d9f1a594 100644
--- a/protocol/triple/options.go
+++ b/global/protocol_client_config.go
@@ -15,32 +15,36 @@
  * limitations under the License.
  */
 
-package triple
+package global
 
-type ServerOptions struct {
-}
+import (
+       "dubbo.apache.org/dubbo-go/v3/common/constant"
+)
 
-func defaultServerOptions() *ServerOptions {
-       return &ServerOptions{}
-}
+// TODO: find a better name replace ProtocolClientConfig
+type ProtocolClientConfig struct {
+       // TODO: maybe we could use this field
+       Name string `yaml:"name" json:"name,omitempty" property:"name"`
 
-func NewServerOptions(opts ...ServerOption) *ServerOptions {
-       defSrvOpts := defaultServerOptions()
-       for _, opt := range opts {
-               opt(defSrvOpts)
-       }
-       return defSrvOpts
+       TripleConfig *TripleConfig `yaml:"triple" json:"triple,omitempty" 
property:"triple"`
 }
 
-func (srvOpts *ServerOptions) init(opts ...ServerOption) {
-       for _, opt := range opts {
-               opt(srvOpts)
+// DefaultProtocolConfig returns a default ProtocolConfig instance.
+func DefaultProtocolClientConfig() *ProtocolClientConfig {
+       return &ProtocolClientConfig{
+               Name:         constant.TriProtocol,
+               TripleConfig: DefaultTripleConfig(),
        }
 }
 
-type ServerOption func(*ServerOptions)
+// Clone a new ProtocolConfig
+func (c *ProtocolClientConfig) Clone() *ProtocolClientConfig {
+       if c == nil {
+               return nil
+       }
 
-func WithServerEmtryOption() ServerOption {
-       return func(opts *ServerOptions) {
+       return &ProtocolClientConfig{
+               Name:         c.Name,
+               TripleConfig: c.TripleConfig.Clone(),
        }
 }
diff --git a/global/protocol_config.go b/global/protocol_config.go
index a70b6d38f..8c89f2ea9 100644
--- a/global/protocol_config.go
+++ b/global/protocol_config.go
@@ -27,23 +27,34 @@ import (
 
 // ProtocolConfig is protocol configuration
 type ProtocolConfig struct {
-       Name   string `yaml:"name" json:"name,omitempty" property:"name"`
-       Ip     string `yaml:"ip"  json:"ip,omitempty" property:"ip"`
-       Port   string `yaml:"port" json:"port,omitempty" property:"port"`
-       Params any    `yaml:"params" json:"params,omitempty" property:"params"`
+       Name string `yaml:"name" json:"name,omitempty" property:"name"`
+       Ip   string `yaml:"ip"  json:"ip,omitempty" property:"ip"`
+       Port string `yaml:"port" json:"port,omitempty" property:"port"`
 
+       // TODO: maybe Params is useless, find a ideal way to config dubbo 
protocol, ref: TripleConfig.
+       Params any `yaml:"params" json:"params,omitempty" property:"params"`
+
+       TripleConfig *TripleConfig `yaml:"triple" json:"triple,omitempty" 
property:"triple"`
+
+       // TODO: remove MaxServerSendMsgSize and MaxServerRecvMsgSize when 
version 4.0.0
+       //
        // MaxServerSendMsgSize max size of server send message, 
1mb=1000kb=1000000b 1mib=1024kb=1048576b.
        // more detail to see 
https://pkg.go.dev/github.com/dustin/go-humanize#pkg-constants
+       // Deprecated:use TripleConfig
        MaxServerSendMsgSize string `yaml:"max-server-send-msg-size" 
json:"max-server-send-msg-size,omitempty"`
+       // TODO: remove MaxServerSendMsgSize and MaxServerRecvMsgSize when 
version 4.0.0
+       //
        // MaxServerRecvMsgSize max size of server receive message
+       // Deprecated:use TripleConfig
        MaxServerRecvMsgSize string `default:"4mib" 
yaml:"max-server-recv-msg-size" json:"max-server-recv-msg-size,omitempty"`
 }
 
 // DefaultProtocolConfig returns a default ProtocolConfig instance.
 func DefaultProtocolConfig() *ProtocolConfig {
        return &ProtocolConfig{
-               Name: constant.TriProtocol,
-               Port: strconv.Itoa(constant.DefaultPort),
+               Name:         constant.TriProtocol,
+               Port:         strconv.Itoa(constant.DefaultPort),
+               TripleConfig: DefaultTripleConfig(),
        }
 }
 
@@ -58,6 +69,7 @@ func (c *ProtocolConfig) Clone() *ProtocolConfig {
                Ip:                   c.Ip,
                Port:                 c.Port,
                Params:               c.Params,
+               TripleConfig:         c.TripleConfig.Clone(),
                MaxServerSendMsgSize: c.MaxServerSendMsgSize,
                MaxServerRecvMsgSize: c.MaxServerRecvMsgSize,
        }
diff --git a/global/reference_config.go b/global/reference_config.go
index 4519df285..013068a94 100644
--- a/global/reference_config.go
+++ b/global/reference_config.go
@@ -23,30 +23,36 @@ import (
 
 // ReferenceConfig is the configuration of service consumer
 type ReferenceConfig struct {
-       InterfaceName     string            `yaml:"interface"  
json:"interface,omitempty" property:"interface"`
-       Check             *bool             `yaml:"check"  
json:"check,omitempty" property:"check"`
-       URL               string            `yaml:"url"  json:"url,omitempty" 
property:"url"`
-       Filter            string            `yaml:"filter" 
json:"filter,omitempty" property:"filter"`
-       Protocol          string            `yaml:"protocol"  
json:"protocol,omitempty" property:"protocol"`
-       RegistryIDs       []string          `yaml:"registry-ids"  
json:"registry-ids,omitempty"  property:"registry-ids"`
-       Cluster           string            `yaml:"cluster"  
json:"cluster,omitempty" property:"cluster"`
-       Loadbalance       string            `yaml:"loadbalance"  
json:"loadbalance,omitempty" property:"loadbalance"`
-       Retries           string            `yaml:"retries"  
json:"retries,omitempty" property:"retries"`
-       Group             string            `yaml:"group"  
json:"group,omitempty" property:"group"`
-       Version           string            `yaml:"version"  
json:"version,omitempty" property:"version"`
-       Serialization     string            `yaml:"serialization" 
json:"serialization" property:"serialization"`
-       ProvidedBy        string            `yaml:"provided_by"  
json:"provided_by,omitempty" property:"provided_by"`
-       Methods           []*MethodConfig   `yaml:"methods"  
json:"methods,omitempty" property:"methods"`
-       Async             bool              `yaml:"async"  
json:"async,omitempty" property:"async"`
-       Params            map[string]string `yaml:"params"  
json:"params,omitempty" property:"params"`
-       Generic           string            `yaml:"generic"  
json:"generic,omitempty" property:"generic"`
-       Sticky            bool              `yaml:"sticky"   
json:"sticky,omitempty" property:"sticky"`
-       RequestTimeout    string            `yaml:"timeout"  
json:"timeout,omitempty" property:"timeout"`
-       ForceTag          bool              `yaml:"force.tag"  
json:"force.tag,omitempty" property:"force.tag"`
-       TracingKey        string            `yaml:"tracing-key" 
json:"tracing-key,omitempty" propertiy:"tracing-key"`
-       MeshProviderPort  int               `yaml:"mesh-provider-port" 
json:"mesh-provider-port,omitempty" propertiy:"mesh-provider-port"`
-       KeepAliveInterval string            `yaml:"keep-alive-interval" 
json:"keep-alive-interval,omitempty" property:"keep-alive-interval"`
-       KeepAliveTimeout  string            `yaml:"keep-alive-timeout" 
json:"keep-alive-timeout,omitempty" property:"keep-alive-timeout"`
+       InterfaceName    string            `yaml:"interface"  
json:"interface,omitempty" property:"interface"`
+       Check            *bool             `yaml:"check"  
json:"check,omitempty" property:"check"`
+       URL              string            `yaml:"url"  json:"url,omitempty" 
property:"url"`
+       Filter           string            `yaml:"filter" 
json:"filter,omitempty" property:"filter"`
+       Protocol         string            `yaml:"protocol"  
json:"protocol,omitempty" property:"protocol"`
+       RegistryIDs      []string          `yaml:"registry-ids"  
json:"registry-ids,omitempty"  property:"registry-ids"`
+       Cluster          string            `yaml:"cluster"  
json:"cluster,omitempty" property:"cluster"`
+       Loadbalance      string            `yaml:"loadbalance"  
json:"loadbalance,omitempty" property:"loadbalance"`
+       Retries          string            `yaml:"retries"  
json:"retries,omitempty" property:"retries"`
+       Group            string            `yaml:"group"  
json:"group,omitempty" property:"group"`
+       Version          string            `yaml:"version"  
json:"version,omitempty" property:"version"`
+       Serialization    string            `yaml:"serialization" 
json:"serialization" property:"serialization"`
+       ProvidedBy       string            `yaml:"provided_by"  
json:"provided_by,omitempty" property:"provided_by"`
+       Async            bool              `yaml:"async"  
json:"async,omitempty" property:"async"`
+       Params           map[string]string `yaml:"params"  
json:"params,omitempty" property:"params"`
+       Generic          string            `yaml:"generic"  
json:"generic,omitempty" property:"generic"`
+       Sticky           bool              `yaml:"sticky"   
json:"sticky,omitempty" property:"sticky"`
+       RequestTimeout   string            `yaml:"timeout"  
json:"timeout,omitempty" property:"timeout"`
+       ForceTag         bool              `yaml:"force.tag"  
json:"force.tag,omitempty" property:"force.tag"`
+       TracingKey       string            `yaml:"tracing-key" 
json:"tracing-key,omitempty" property:"tracing-key"`
+       MeshProviderPort int               `yaml:"mesh-provider-port" 
json:"mesh-provider-port,omitempty" property:"mesh-provider-port"`
+
+       // config
+       MethodsConfig        []*MethodConfig       `yaml:"methods"  
json:"methods,omitempty" property:"methods"`
+       ProtocolClientConfig *ProtocolClientConfig `yaml:"protocol-config" 
json:"protocol-config,omitempty" property:"protocol-config"`
+
+       // TODO: Deprecated:use TripleConfig
+       // remove KeepAliveInterval and KeepAliveInterval in version 4.0.0
+       KeepAliveInterval string `yaml:"keep-alive-interval" 
json:"keep-alive-interval,omitempty" property:"keep-alive-interval"`
+       KeepAliveTimeout  string `yaml:"keep-alive-timeout" 
json:"keep-alive-timeout,omitempty" property:"keep-alive-timeout"`
 
        // just for new triple non-IDL mode
        // TODO: remove IDLMode when config package is removed
@@ -57,11 +63,13 @@ func DefaultReferenceConfig() *ReferenceConfig {
        return &ReferenceConfig{
                // use Triple protocol by default
                //Protocol: "tri",
-               Methods: make([]*MethodConfig, 0, 8),
+               MethodsConfig:        make([]*MethodConfig, 0, 8),
+               ProtocolClientConfig: DefaultProtocolClientConfig(),
                //Params:   make(map[string]string, 8),
        }
 }
 
+// TODO: check if ProtocolClientConfig need get options
 func (c *ReferenceConfig) GetOptions() []ReferenceOption {
        var refOpts []ReferenceOption
        if c.InterfaceName != "" {
@@ -152,9 +160,9 @@ func (c *ReferenceConfig) Clone() *ReferenceConfig {
        copy(newRegistryIDs, c.RegistryIDs)
 
        var newMethods []*MethodConfig
-       if c.Methods != nil {
-               newMethods = make([]*MethodConfig, 0, len(c.Methods))
-               for _, method := range c.Methods {
+       if c.MethodsConfig != nil {
+               newMethods = make([]*MethodConfig, 0, len(c.MethodsConfig))
+               for _, method := range c.MethodsConfig {
                        newMethods = append(newMethods, method.Clone())
                }
        }
@@ -165,31 +173,32 @@ func (c *ReferenceConfig) Clone() *ReferenceConfig {
        }
 
        return &ReferenceConfig{
-               InterfaceName:     c.InterfaceName,
-               Check:             newCheck,
-               URL:               c.URL,
-               Filter:            c.Filter,
-               Protocol:          c.Protocol,
-               RegistryIDs:       newRegistryIDs,
-               Cluster:           c.Cluster,
-               Loadbalance:       c.Loadbalance,
-               Retries:           c.Retries,
-               Group:             c.Group,
-               Version:           c.Version,
-               Serialization:     c.Serialization,
-               ProvidedBy:        c.ProvidedBy,
-               Methods:           newMethods,
-               Async:             c.Async,
-               Params:            newParams,
-               Generic:           c.Generic,
-               Sticky:            c.Sticky,
-               RequestTimeout:    c.RequestTimeout,
-               ForceTag:          c.ForceTag,
-               TracingKey:        c.TracingKey,
-               MeshProviderPort:  c.MeshProviderPort,
-               KeepAliveInterval: c.KeepAliveInterval,
-               KeepAliveTimeout:  c.KeepAliveTimeout,
-               IDLMode:           c.IDLMode,
+               InterfaceName:        c.InterfaceName,
+               Check:                newCheck,
+               URL:                  c.URL,
+               Filter:               c.Filter,
+               Protocol:             c.Protocol,
+               RegistryIDs:          newRegistryIDs,
+               Cluster:              c.Cluster,
+               Loadbalance:          c.Loadbalance,
+               Retries:              c.Retries,
+               Group:                c.Group,
+               Version:              c.Version,
+               Serialization:        c.Serialization,
+               ProvidedBy:           c.ProvidedBy,
+               MethodsConfig:        newMethods,
+               ProtocolClientConfig: c.ProtocolClientConfig.Clone(),
+               Async:                c.Async,
+               Params:               newParams,
+               Generic:              c.Generic,
+               Sticky:               c.Sticky,
+               RequestTimeout:       c.RequestTimeout,
+               ForceTag:             c.ForceTag,
+               TracingKey:           c.TracingKey,
+               MeshProviderPort:     c.MeshProviderPort,
+               KeepAliveInterval:    c.KeepAliveInterval,
+               KeepAliveTimeout:     c.KeepAliveTimeout,
+               IDLMode:              c.IDLMode,
        }
 }
 
diff --git a/global/triple_config.go b/global/triple_config.go
new file mode 100644
index 000000000..a5fcf7a86
--- /dev/null
+++ b/global/triple_config.go
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package global
+
+// TODO: Should the server and client configurations be separated?
+type TripleConfig struct {
+       KeepAliveInterval string `yaml:"keep-alive-interval" 
json:"keep-alive-interval,omitempty" property:"keep-alive-interval"`
+       KeepAliveTimeout  string `yaml:"keep-alive-timeout" 
json:"keep-alive-timeout,omitempty" property:"keep-alive-timeout"`
+
+       // MaxServerSendMsgSize max size of server send message, 
1mb=1000kb=1000000b 1mib=1024kb=1048576b.
+       // more detail to see 
https://pkg.go.dev/github.com/dustin/go-humanize#pkg-constants
+       MaxServerSendMsgSize string `yaml:"max-server-send-msg-size" 
json:"max-server-send-msg-size,omitempty"` // MaxServerRecvMsgSize max size of 
server receive message
+       MaxServerRecvMsgSize string `yaml:"max-server-recv-msg-size" 
json:"max-server-recv-msg-size,omitempty"`
+}
+
+func DefaultTripleConfig() *TripleConfig {
+       return &TripleConfig{}
+}
+
+// Clone a new TripleConfig
+func (t *TripleConfig) Clone() *TripleConfig {
+       if t == nil {
+               return nil
+       }
+
+       return &TripleConfig{
+               KeepAliveInterval:    t.KeepAliveInterval,
+               KeepAliveTimeout:     t.KeepAliveTimeout,
+               MaxServerSendMsgSize: t.MaxServerSendMsgSize,
+               MaxServerRecvMsgSize: t.MaxServerRecvMsgSize,
+       }
+}
diff --git a/metadata/metadata_service_test.go 
b/metadata/metadata_service_test.go
index 4f2517af4..7321d950f 100644
--- a/metadata/metadata_service_test.go
+++ b/metadata/metadata_service_test.go
@@ -312,7 +312,7 @@ func Test_serviceExporterExport(t *testing.T) {
                opts := &Options{
                        appName:      "dubbo-app",
                        metadataType: constant.RemoteMetadataStorageType,
-                       protocol:     constant.Dubbo,
+                       protocol:     constant.DubboProtocol,
                        port:         p,
                }
                dubboProtocol.On("Export").Return(mockExporter).Once()
@@ -331,7 +331,7 @@ func Test_serviceExporterExport(t *testing.T) {
                opts := &Options{
                        appName:      "dubbo-app",
                        metadataType: constant.RemoteMetadataStorageType,
-                       protocol:     constant.Dubbo,
+                       protocol:     constant.DubboProtocol,
                        port:         p,
                }
                e := &serviceExporter{
@@ -345,7 +345,7 @@ func Test_serviceExporterExport(t *testing.T) {
                opts := &Options{
                        appName:      "dubbo-app",
                        metadataType: constant.RemoteMetadataStorageType,
-                       protocol:     constant.Dubbo,
+                       protocol:     constant.DubboProtocol,
                        port:         0,
                }
                // UnRegister first otherwise will fail
diff --git a/options.go b/options.go
index b8c5f6ff3..61a713e20 100644
--- a/options.go
+++ b/options.go
@@ -379,8 +379,27 @@ func WithMetadataServiceProtocol(protocol string) 
InstanceOption {
        }
 }
 
-func WithProtocol(opts ...protocol.Option) InstanceOption {
-       proOpts := protocol.NewOptions(opts...)
+// TODO: deal this fuction
+// this function I want handle the protocol.Option which
+// both server and client can use together.
+// like:
+//
+//     func WithProtocol(opts ...protocol.Option) InstanceOption {
+//             proOpts := protocol.NewOptions(opts...)
+//
+//             log.Warnf("proOpts: %+v", proOpts)
+//
+//             return func(insOpts *InstanceOptions) {
+//                     if insOpts.Protocols == nil {
+//                             insOpts.Protocols = 
make(map[string]*global.ProtocolConfig)
+//                     }
+//                     insOpts.Protocols[proOpts.ID] = proOpts.Protocol
+//             }
+//     }
+//
+// but now only work in server side for compat old API.
+func WithProtocol(opts ...protocol.ServerOption) InstanceOption {
+       proOpts := protocol.NewServerOptions(opts...)
 
        return func(insOpts *InstanceOptions) {
                if insOpts.Protocols == nil {
diff --git a/protocol/options.go b/protocol/options.go
index ecb955c29..c3f1e58e2 100644
--- a/protocol/options.go
+++ b/protocol/options.go
@@ -27,20 +27,84 @@ import (
        "dubbo.apache.org/dubbo-go/v3/protocol/triple"
 )
 
-type Options struct {
+type ClientOption interface {
+       applyToClient(*ClientOptions)
+}
+
+type ServerOption interface {
+       applyToServer(*ServerOptions)
+}
+
+type Option interface {
+       ClientOption
+       ServerOption
+}
+
+// WithClientOptions composes multiple ClientOptions into one.
+func WithClientOptions(options ...ClientOption) ClientOption {
+       return &clientOptionsOption{options}
+}
+
+type clientOptionsOption struct {
+       options []ClientOption
+}
+
+func (o *clientOptionsOption) applyToClient(config *ClientOptions) {
+       for _, option := range o.options {
+               option.applyToClient(config)
+       }
+}
+
+// WithServerOptions composes multiple ServerOptions into one.
+func WithServerOptions(options ...ServerOption) ServerOption {
+       return &serverOptionsOption{options}
+}
+
+type serverOptionsOption struct {
+       options []ServerOption
+}
+
+func (o *serverOptionsOption) applyToServer(config *ServerOptions) {
+       for _, option := range o.options {
+               option.applyToServer(config)
+       }
+}
+
+// WithOptions composes multiple Options into one.
+func WithOptions(options ...Option) Option {
+       return &optionsOption{options}
+}
+
+type optionsOption struct {
+       options []Option
+}
+
+func (o *optionsOption) applyToClient(config *ClientOptions) {
+       for _, option := range o.options {
+               option.applyToClient(config)
+       }
+}
+
+func (o *optionsOption) applyToServer(config *ServerOptions) {
+       for _, option := range o.options {
+               option.applyToServer(config)
+       }
+}
+
+type ServerOptions struct {
        Protocol *global.ProtocolConfig
 
        ID string
 }
 
-func defaultOptions() *Options {
-       return &Options{Protocol: global.DefaultProtocolConfig()}
+func defaultServerOptions() *ServerOptions {
+       return &ServerOptions{Protocol: global.DefaultProtocolConfig()}
 }
 
-func NewOptions(opts ...Option) *Options {
-       defOpts := defaultOptions()
+func NewServerOptions(opts ...ServerOption) *ServerOptions {
+       defOpts := defaultServerOptions()
        for _, opt := range opts {
-               opt(defOpts)
+               opt.applyToServer(defOpts)
        }
 
        if defOpts.ID == "" {
@@ -55,75 +119,196 @@ func NewOptions(opts ...Option) *Options {
        return defOpts
 }
 
-type Option func(*Options)
+type ClientOptions struct {
+       ProtocolClient *global.ProtocolClientConfig
 
-func WithDubbo() Option {
-       return func(opts *Options) {
-               opts.Protocol.Name = "dubbo"
+       ID string
+}
+
+func defaultClientOptions() *ClientOptions {
+       return &ClientOptions{ProtocolClient: 
global.DefaultProtocolClientConfig()}
+}
+
+func NewClientOptions(opts ...ClientOption) *ClientOptions {
+       defOpts := defaultClientOptions()
+       for _, opt := range opts {
+               opt.applyToClient(defOpts)
+       }
+
+       if defOpts.ID == "" {
+               if defOpts.ProtocolClient.Name == "" {
+                       // should be the same as default value of 
config.ProtocolConfig.Protocol
+                       defOpts.ID = constant.TriProtocol
+               } else {
+                       defOpts.ID = defOpts.ProtocolClient.Name
+               }
        }
+
+       return defOpts
 }
 
-func WithJSONRPC() Option {
-       return func(opts *Options) {
-               opts.Protocol.Name = "jsonrpc"
+type tripleOption struct {
+       triOpts triple.Options
+}
+
+func (o *tripleOption) applyToClient(config *ClientOptions) {
+       config.ProtocolClient.TripleConfig = o.triOpts.Triple
+}
+
+func (o *tripleOption) applyToServer(config *ServerOptions) {
+       config.Protocol.TripleConfig = o.triOpts.Triple
+}
+
+func WithTriple(opts ...triple.Option) Option {
+       triSrvOpts := triple.NewOptions(opts...)
+
+       return &tripleOption{
+               triOpts: *triSrvOpts,
        }
 }
 
+type dubboOption struct{}
+
+func (o *dubboOption) applyToClient(config *ClientOptions) {
+       config.ProtocolClient.Name = constant.DubboProtocol
+}
+
+func (o *dubboOption) applyToServer(config *ServerOptions) {
+       config.Protocol.Name = constant.DubboProtocol
+}
+
+// TODO: Maybe we need configure dubbo protocol future.
+func WithDubbo() Option {
+       return &dubboOption{}
+}
+
+type jsonRPCOption struct{}
+
+func (o *jsonRPCOption) applyToClient(config *ClientOptions) {
+       config.ProtocolClient.Name = constant.JSONRPCProtocol
+}
+
+func (o *jsonRPCOption) applyToServer(config *ServerOptions) {
+       config.Protocol.Name = constant.JSONRPCProtocol
+}
+
+// TODO: Maybe we need configure jsonRPC protocol future.
+func WithJSONRPC() Option {
+       return &jsonRPCOption{}
+}
+
+type restOption struct{}
+
+func (o *restOption) applyToClient(config *ClientOptions) {
+       config.ProtocolClient.Name = constant.RESTProtocol
+}
+
+func (o *restOption) applyToServer(config *ServerOptions) {
+       config.Protocol.Name = constant.RESTProtocol
+}
+
+// TODO: Maybe we need configure REST protocol future.
 func WithREST() Option {
-       return func(opts *Options) {
-               opts.Protocol.Name = "rest"
-       }
+       return &restOption{}
+}
+
+type protocolNameOption struct {
+       Name string
 }
 
-func WithTriple(opts ...triple.ServerOption) Option {
-       triSrvOpts := triple.NewServerOptions()
+func (o *protocolNameOption) applyToClient(config *ClientOptions) {
+       config.ProtocolClient.Name = o.Name
+}
 
-       return func(opts *Options) {
-               opts.Protocol.Name = "tri"
-               opts.Protocol.Params = triSrvOpts
-       }
+func (o *protocolNameOption) applyToServer(config *ServerOptions) {
+       config.Protocol.Name = o.Name
 }
 
+// NOTE: This option can't be configured freely.
 func WithProtocol(p string) Option {
-       return func(opts *Options) {
-               opts.Protocol.Name = p
-       }
+       return &protocolNameOption{p}
+}
+
+type idOption struct {
+       ID string
+}
+
+func (o *idOption) applyToServer(config *ServerOptions) {
+       config.ID = o.ID
 }
 
 // WithID specifies the id of protocol.Options. Then you could configure 
server.WithProtocolIDs and
 // server.WithServer_ProtocolIDs to specify which protocol you need to use in 
multi-protocols scenario.
-func WithID(id string) Option {
-       return func(opts *Options) {
-               opts.ID = id
-       }
+func WithID(id string) ServerOption {
+       return &idOption{id}
 }
 
-func WithIp(ip string) Option {
-       return func(opts *Options) {
-               opts.Protocol.Ip = ip
-       }
+type ipOption struct {
+       Ip string
 }
 
-func WithPort(port int) Option {
-       return func(opts *Options) {
-               opts.Protocol.Port = strconv.Itoa(port)
-       }
+func (o *ipOption) applyToServer(config *ServerOptions) {
+       config.Protocol.Ip = o.Ip
 }
 
-func WithParams(params any) Option {
-       return func(opts *Options) {
-               opts.Protocol.Params = params
-       }
+func WithIp(ip string) ServerOption {
+       return &ipOption{ip}
 }
 
-func WithMaxServerSendMsgSize(size int) Option {
-       return func(opts *Options) {
-               opts.Protocol.MaxServerSendMsgSize = strconv.Itoa(size)
-       }
+type portOption struct {
+       Port string
 }
 
-func WithMaxServerRecvMsgSize(size int) Option {
-       return func(opts *Options) {
-               opts.Protocol.MaxServerRecvMsgSize = strconv.Itoa(size)
-       }
+func (o *portOption) applyToServer(config *ServerOptions) {
+       config.Protocol.Port = o.Port
+}
+
+func WithPort(port int) ServerOption {
+       return &portOption{strconv.Itoa(port)}
+}
+
+type paramsOption struct {
+       Params any
+}
+
+func (o *paramsOption) applyToServer(config *ServerOptions) {
+       config.Protocol.Params = o.Params
+}
+
+func WithParams(params any) ServerOption {
+       return &paramsOption{params}
+}
+
+// TODO: remove MaxServerSendMsgSize and MaxServerRecvMsgSize when version 
4.0.0
+type maxServerSendMsgSizeOption struct {
+       MaxServerSendMsgSize string
+}
+
+// TODO: remove MaxServerSendMsgSize and MaxServerRecvMsgSize when version 
4.0.0
+func (o *maxServerSendMsgSizeOption) applyToServer(config *ServerOptions) {
+       config.Protocol.MaxServerSendMsgSize = o.MaxServerSendMsgSize
+}
+
+// TODO: remove MaxServerSendMsgSize and MaxServerRecvMsgSize when version 
4.0.0
+//
+// Deprecated:use triple.WithMaxServerSendMsgSize instead.
+func WithMaxServerSendMsgSize(size string) ServerOption {
+       return &maxServerSendMsgSizeOption{size}
+}
+
+// TODO: remove MaxServerSendMsgSize and MaxServerRecvMsgSize when version 
4.0.0
+type maxServerRecvMsgSize struct {
+       MaxServerRecvMsgSize string
+}
+
+// TODO: remove MaxServerSendMsgSize and MaxServerRecvMsgSize when version 
4.0.0
+func (o *maxServerRecvMsgSize) applyToServer(config *ServerOptions) {
+       config.Protocol.MaxServerRecvMsgSize = o.MaxServerRecvMsgSize
+}
+
+// TODO: remove MaxServerSendMsgSize and MaxServerRecvMsgSize when version 
4.0.0
+//
+// Deprecated: use triple.WithMaxServerRecvMsgSize instead.
+func WithMaxServerRecvMsgSize(size string) ServerOption {
+       return &maxServerRecvMsgSize{size}
 }
diff --git a/protocol/triple/client.go b/protocol/triple/client.go
index ad70e86cb..9300bee68 100644
--- a/protocol/triple/client.go
+++ b/protocol/triple/client.go
@@ -26,6 +26,7 @@ import (
        "net/http"
        "reflect"
        "strings"
+       "time"
 )
 
 import (
@@ -58,6 +59,9 @@ type clientManager struct {
        triClients map[string]*tri.Client
 }
 
+// TODO: code a triple client between clientManager and triple_protocol client
+// TODO: write a NewClient for triple client
+
 func (cm *clientManager) getClient(method string) (*tri.Client, error) {
        triClient, ok := cm.triClients[method]
        if !ok {
@@ -139,22 +143,8 @@ func (cm *clientManager) close() error {
 // newClientManager extracts configurations from url and builds clientManager
 func newClientManager(url *common.URL) (*clientManager, error) {
        var cliOpts []tri.ClientOption
-
-       // set max send and recv msg size
-       maxCallRecvMsgSize := constant.DefaultMaxCallRecvMsgSize
-       if recvMsgSize, err := 
humanize.ParseBytes(url.GetParam(constant.MaxCallRecvMsgSize, "")); err == nil 
&& recvMsgSize > 0 {
-               maxCallRecvMsgSize = int(recvMsgSize)
-       }
-       cliOpts = append(cliOpts, tri.WithReadMaxBytes(maxCallRecvMsgSize))
-       maxCallSendMsgSize := constant.DefaultMaxCallSendMsgSize
-       if sendMsgSize, err := 
humanize.ParseBytes(url.GetParam(constant.MaxCallSendMsgSize, "")); err == nil 
&& sendMsgSize > 0 {
-               maxCallSendMsgSize = int(sendMsgSize)
-       }
-       cliOpts = append(cliOpts, tri.WithSendMaxBytes(maxCallSendMsgSize))
-       // set keepalive interval and keepalive timeout
-       keepAliveInterval := url.GetParamDuration(constant.KeepAliveInterval, 
constant.DefaultKeepAliveInterval)
-       keepAliveTimeout := url.GetParamDuration(constant.KeepAliveTimeout, 
constant.DefaultKeepAliveTimeout)
        var isIDL bool
+
        // set serialization
        serialization := url.GetParam(constant.SerializationKey, 
constant.ProtobufSerialization)
        switch serialization {
@@ -208,6 +198,14 @@ func newClientManager(url *common.URL) (*clientManager, 
error) {
                }
        }
 
+       cliKeepAliveOpts, keepAliveInterval, keepAliveTimeout, 
genKeepAliveOptsErr := genKeepAliveOpts(url)
+       if genKeepAliveOptsErr != nil {
+               logger.Errorf("genKeepAliveOpts err: %v", genKeepAliveOptsErr)
+               return nil, genKeepAliveOptsErr
+       }
+
+       cliOpts = append(cliOpts, cliKeepAliveOpts...)
+
        var transport http.RoundTripper
        callType := url.GetParam(constant.CallHTTPTypeKey, constant.CallHTTP2)
        switch callType {
@@ -284,6 +282,53 @@ func newClientManager(url *common.URL) (*clientManager, 
error) {
        }, nil
 }
 
+func genKeepAliveOpts(url *common.URL) ([]tri.ClientOption, time.Duration, 
time.Duration, error) {
+       var cliKeepAliveOpts []tri.ClientOption
+
+       // set max send and recv msg size
+       maxCallRecvMsgSize := constant.DefaultMaxCallRecvMsgSize
+       if recvMsgSize, err := 
humanize.ParseBytes(url.GetParam(constant.MaxCallRecvMsgSize, "")); err == nil 
&& recvMsgSize > 0 {
+               maxCallRecvMsgSize = int(recvMsgSize)
+       }
+       cliKeepAliveOpts = append(cliKeepAliveOpts, 
tri.WithReadMaxBytes(maxCallRecvMsgSize))
+       maxCallSendMsgSize := constant.DefaultMaxCallSendMsgSize
+       if sendMsgSize, err := 
humanize.ParseBytes(url.GetParam(constant.MaxCallSendMsgSize, "")); err == nil 
&& sendMsgSize > 0 {
+               maxCallSendMsgSize = int(sendMsgSize)
+       }
+       cliKeepAliveOpts = append(cliKeepAliveOpts, 
tri.WithSendMaxBytes(maxCallSendMsgSize))
+
+       // set keepalive interval and keepalive timeout
+       // Deprecated:use tripleconfig
+       // TODO: remove KeepAliveInterval and KeepAliveInterval in version 4.0.0
+       keepAliveInterval := url.GetParamDuration(constant.KeepAliveInterval, 
constant.DefaultKeepAliveInterval)
+       keepAliveTimeout := url.GetParamDuration(constant.KeepAliveTimeout, 
constant.DefaultKeepAliveTimeout)
+
+       tripleConfRaw, ok := url.GetAttribute(constant.TripleConfigKey)
+       if ok {
+               var parseErr error
+               tripleConf := tripleConfRaw.(*global.TripleConfig)
+
+               if tripleConf == nil {
+                       return cliKeepAliveOpts, keepAliveInterval, 
keepAliveTimeout, nil
+               }
+
+               if tripleConf.KeepAliveInterval != "" {
+                       keepAliveInterval, parseErr = 
time.ParseDuration(tripleConf.KeepAliveInterval)
+                       if parseErr != nil {
+                               return nil, 0, 0, parseErr
+                       }
+               }
+               if tripleConf.KeepAliveTimeout != "" {
+                       keepAliveTimeout, parseErr = 
time.ParseDuration(tripleConf.KeepAliveTimeout)
+                       if parseErr != nil {
+                               return nil, 0, 0, parseErr
+                       }
+               }
+       }
+
+       return cliKeepAliveOpts, keepAliveInterval, keepAliveTimeout, nil
+}
+
 func isFilterHeader(key string) bool {
        if key != "" && key[0] == ':' {
                return true
diff --git a/protocol/triple/dubbo3_invoker.go 
b/protocol/triple/dubbo3_invoker.go
index 627833351..710b1e9f3 100644
--- a/protocol/triple/dubbo3_invoker.go
+++ b/protocol/triple/dubbo3_invoker.go
@@ -100,9 +100,21 @@ func NewDubbo3Invoker(url *common.URL) (*DubboInvoker, 
error) {
        }
        opts = append(opts, 
triConfig.WithGRPCMaxCallRecvMessageSize(maxCallRecvMsgSize))
        opts = append(opts, 
triConfig.WithGRPCMaxCallSendMessageSize(maxCallSendMsgSize))
+
        // grpc keepalive config
+       // Deprecated:use tripleconfig
+       // TODO: remove KeepAliveInterval and KeepAliveInterval in version 4.0.0
        keepAliveInterval := url.GetParamDuration(constant.KeepAliveInterval, 
constant.DefaultKeepAliveInterval)
        keepAliveTimeout := url.GetParamDuration(constant.KeepAliveTimeout, 
constant.DefaultKeepAliveTimeout)
+
+       tripleConfRaw, ok := url.GetAttribute(constant.TripleConfigKey)
+       if ok {
+               tripleConf := tripleConfRaw.(*global.TripleConfig)
+               // TODO: handle ParseDuration error
+               keepAliveInterval, _ = 
time.ParseDuration(tripleConf.KeepAliveInterval)
+               keepAliveTimeout, _ = 
time.ParseDuration(tripleConf.KeepAliveTimeout)
+       }
+
        opts = append(opts, 
triConfig.WithGRPCKeepAliveTimeInterval(keepAliveInterval))
        opts = append(opts, 
triConfig.WithGRPCKeepAliveTimeout(keepAliveTimeout))
 
diff --git a/protocol/triple/options.go b/protocol/triple/options.go
index 239de2333..b1b634a52 100644
--- a/protocol/triple/options.go
+++ b/protocol/triple/options.go
@@ -17,30 +17,78 @@
 
 package triple
 
-type ServerOptions struct {
+import (
+       "time"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/global"
+)
+
+// TODO: The triple options for the server and client are mixed together now.
+// We need to find a way to separate them later.
+
+type Options struct {
+       Triple *global.TripleConfig
 }
 
-func defaultServerOptions() *ServerOptions {
-       return &ServerOptions{}
+func defaultOptions() *Options {
+       return &Options{Triple: global.DefaultTripleConfig()}
 }
 
-func NewServerOptions(opts ...ServerOption) *ServerOptions {
-       defSrvOpts := defaultServerOptions()
+func NewOptions(opts ...Option) *Options {
+       defSrvOpts := defaultOptions()
        for _, opt := range opts {
                opt(defSrvOpts)
        }
        return defSrvOpts
 }
 
-func (srvOpts *ServerOptions) init(opts ...ServerOption) {
-       for _, opt := range opts {
-               opt(srvOpts)
+type Option func(*Options)
+
+// WithKeepAlive sets the keep-alive interval and timeout for the Triple 
protocol.
+// interval: The duration between keep-alive pings.
+// timeout: The duration to wait for a keep-alive response before considering 
the connection dead.
+// If not set, default interval is 10s, default timeout is 20s.
+func WithKeepAlive(interval, timeout time.Duration) Option {
+       return func(opts *Options) {
+               opts.Triple.KeepAliveInterval = interval.String()
+               opts.Triple.KeepAliveTimeout = timeout.String()
        }
 }
 
-type ServerOption func(*ServerOptions)
+// WithKeepAliveInterval sets the keep-alive interval for the Triple protocol.
+// interval: The duration between keep-alive pings.
+// If not set, default interval is 10s.
+func WithKeepAliveInterval(interval time.Duration) Option {
+       return func(opts *Options) {
+               opts.Triple.KeepAliveInterval = interval.String()
+       }
+}
+
+// WithKeepAliveTimeout sets the keep-alive timeout for the Triple protocol.
+// timeout: The duration to wait for a keep-alive response before considering 
the connection dead.
+// If not set, default timeout is 20s.
+func WithKeepAliveTimeout(timeout time.Duration) Option {
+       return func(opts *Options) {
+               opts.Triple.KeepAliveTimeout = timeout.String()
+       }
+}
+
+// WithMaxServerSendMsgSize sets the maximum size of messages that the server 
can send.
+// size: The maximum message size in bytes, specified as a string (e.g., 
"4MB").
+// If not set, default value is 2147MB (math.MaxInt32).
+func WithMaxServerSendMsgSize(size string) Option {
+       return func(opts *Options) {
+               opts.Triple.MaxServerSendMsgSize = size
+       }
+}
 
-func WithServerEmtryOption() ServerOption {
-       return func(opts *ServerOptions) {
+// WithMaxServerRecvMsgSize sets the maximum size of messages that the server 
can receive.
+// size: The maximum message size in bytes, specified as a string (e.g., 
"4MB").
+// If not set, default value is 4MB (4194304 bytes).
+func WithMaxServerRecvMsgSize(size string) Option {
+       return func(opts *Options) {
+               opts.Triple.MaxServerRecvMsgSize = size
        }
 }
diff --git a/protocol/triple/server.go b/protocol/triple/server.go
index f9282614b..6f28c84cf 100644
--- a/protocol/triple/server.go
+++ b/protocol/triple/server.go
@@ -56,18 +56,15 @@ import (
 // provide functionality.
 type Server struct {
        triServer *tri.Server
-       cfg       *ServerOptions
+       cfg       *global.TripleConfig
        mu        sync.RWMutex
        services  map[string]grpc.ServiceInfo
 }
 
 // NewServer creates a new TRIPLE server.
-// triServer would not be initialized since we could not get configurations 
here.
-func NewServer(opts ...ServerOption) *Server {
-       newSrvOpts := defaultServerOptions()
-       newSrvOpts.init(opts...)
+func NewServer(cfg *global.TripleConfig) *Server {
        return &Server{
-               cfg:      newSrvOpts,
+               cfg:      cfg,
                services: make(map[string]grpc.ServiceInfo),
        }
 }
@@ -175,6 +172,12 @@ func (s *Server) RefreshService(invoker base.Invoker, info 
*common.ServiceInfo)
 }
 
 func getHanOpts(url *common.URL) (hanOpts []tri.HandlerOption) {
+       group := url.GetParam(constant.GroupKey, "")
+       version := url.GetParam(constant.VersionKey, "")
+       hanOpts = append(hanOpts, tri.WithGroup(group), 
tri.WithVersion(version))
+
+       // Deprecated:use TripleConfig
+       // TODO: remove MaxServerSendMsgSize and MaxServerRecvMsgSize when 
version 4.0.0
        var err error
        maxServerRecvMsgSize := constant.DefaultMaxServerRecvMsgSize
        if recvMsgSize, convertErr := 
humanize.ParseBytes(url.GetParam(constant.MaxServerRecvMsgSize, "")); 
convertErr == nil && recvMsgSize != 0 {
@@ -182,17 +185,43 @@ func getHanOpts(url *common.URL) (hanOpts 
[]tri.HandlerOption) {
        }
        hanOpts = append(hanOpts, tri.WithReadMaxBytes(maxServerRecvMsgSize))
 
+       // Deprecated:use TripleConfig
+       // TODO: remove MaxServerSendMsgSize and MaxServerRecvMsgSize when 
version 4.0.0
        maxServerSendMsgSize := constant.DefaultMaxServerSendMsgSize
        if sendMsgSize, convertErr := 
humanize.ParseBytes(url.GetParam(constant.MaxServerSendMsgSize, "")); err == 
convertErr && sendMsgSize != 0 {
                maxServerSendMsgSize = int(sendMsgSize)
        }
        hanOpts = append(hanOpts, tri.WithSendMaxBytes(maxServerSendMsgSize))
 
+       var tripleConf *global.TripleConfig
+
+       tripleConfRaw, ok := url.GetAttribute(constant.TripleConfigKey)
+       if ok {
+               tripleConf = tripleConfRaw.(*global.TripleConfig)
+       }
+
+       if tripleConf == nil {
+               return hanOpts
+       }
+
+       if tripleConf.MaxServerRecvMsgSize != "" {
+               logger.Warnf("MaxServerRecvMsgSize: %v", 
tripleConf.MaxServerRecvMsgSize)
+               if recvMsgSize, convertErr := 
humanize.ParseBytes(tripleConf.MaxServerRecvMsgSize); convertErr == nil && 
recvMsgSize != 0 {
+                       maxServerRecvMsgSize = int(recvMsgSize)
+               }
+               hanOpts = append(hanOpts, 
tri.WithReadMaxBytes(maxServerRecvMsgSize))
+       }
+
+       if tripleConf.MaxServerSendMsgSize != "" {
+               logger.Warnf("MaxServerSendMsgSize: %v", 
tripleConf.MaxServerSendMsgSize)
+               if sendMsgSize, convertErr := 
humanize.ParseBytes(tripleConf.MaxServerSendMsgSize); err == convertErr && 
sendMsgSize != 0 {
+                       maxServerSendMsgSize = int(sendMsgSize)
+               }
+               hanOpts = append(hanOpts, 
tri.WithSendMaxBytes(maxServerSendMsgSize))
+       }
+
        // todo:// open tracing
 
-       group := url.GetParam(constant.GroupKey, "")
-       version := url.GetParam(constant.VersionKey, "")
-       hanOpts = append(hanOpts, tri.WithGroup(group), 
tri.WithVersion(version))
        return hanOpts
 }
 
diff --git a/protocol/triple/triple.go b/protocol/triple/triple.go
index ddf880d44..86c4e58d5 100644
--- a/protocol/triple/triple.go
+++ b/protocol/triple/triple.go
@@ -30,6 +30,7 @@ import (
        "dubbo.apache.org/dubbo-go/v3/common"
        "dubbo.apache.org/dubbo-go/v3/common/constant"
        "dubbo.apache.org/dubbo-go/v3/common/extension"
+       "dubbo.apache.org/dubbo-go/v3/global"
        "dubbo.apache.org/dubbo-go/v3/internal"
        "dubbo.apache.org/dubbo-go/v3/protocol/base"
 )
@@ -84,10 +85,12 @@ func (tp *TripleProtocol) openServer(invoker base.Invoker, 
info *common.ServiceI
                panic("[TRIPLE Protocol]" + url.Key() + "is not existing")
        }
 
-       // TODO: get triple ServerOptions
-       // srvOpts:= url.GetAttribute(constant.TripleServerOptionsKey)
-       // srv := NewServer(SrvOpts)
-       srv := NewServer()
+       // TODO: handle errors
+       tripleConfRaw, _ := url.GetAttribute(constant.TripleConfigKey)
+       // TODO: verificate the tripleConf
+       tripleConf, _ := tripleConfRaw.(*global.TripleConfig)
+
+       srv := NewServer(tripleConf)
        srv.Start(invoker, info)
        tp.serverMap[url.Location] = srv
 }
diff --git a/registry/polaris/service_discovery.go 
b/registry/polaris/service_discovery.go
index c8971f485..f294b0b8b 100644
--- a/registry/polaris/service_discovery.go
+++ b/registry/polaris/service_discovery.go
@@ -318,7 +318,7 @@ func convertToRegisterInstance(namespace string, instance 
registry.ServiceInstan
                health      = instance.IsHealthy()
                isolate     = instance.IsEnable()
                ttl         = 5
-               protocolVal = string(constant.Dubbo)
+               protocolVal = string(constant.DubboProtocol)
        )
 
        return &api.InstanceRegisterRequest{
diff --git a/server/action.go b/server/action.go
index 4a44b9a8f..82a6043db 100644
--- a/server/action.go
+++ b/server/action.go
@@ -209,11 +209,17 @@ func (svcOpts *ServiceOptions) export(info 
*common.ServiceInfo) error {
                        // TLSConifg
                        common.WithAttribute(constant.TLSConfigKey, 
svcOpts.srvOpts.TLS),
                        common.WithAttribute(constant.RpcServiceKey, 
svcOpts.rpcService),
+                       common.WithAttribute(constant.TripleConfigKey, 
protocolConf.TripleConfig),
                        common.WithToken(svcConf.Token),
                        common.WithParamsValue(constant.MetadataTypeKey, 
svcOpts.metadataType),
+
                        // fix https://github.com/apache/dubbo-go/issues/2176
+                       // TODO: remove MaxServerSendMsgSize value and 
MaxServerRecvMsgSize value when version 4.0.0
+                       // use TripleConfig to transport arguments
                        common.WithParamsValue(constant.MaxServerSendMsgSize, 
protocolConf.MaxServerSendMsgSize),
                        common.WithParamsValue(constant.MaxServerRecvMsgSize, 
protocolConf.MaxServerRecvMsgSize),
+
+                       // TODO: remove IDL value when version 4.0.0
                        common.WithParamsValue(constant.IDLMode, isIDL),
                )
 
diff --git a/server/options.go b/server/options.go
index 6a97eac1f..9c6d48944 100644
--- a/server/options.go
+++ b/server/options.go
@@ -375,8 +375,8 @@ func WithServerProtocolIDs(protocolIDs []string) 
ServerOption {
        }
 }
 
-func WithServerProtocol(opts ...protocol.Option) ServerOption {
-       proOpts := protocol.NewOptions(opts...)
+func WithServerProtocol(opts ...protocol.ServerOption) ServerOption {
+       proOpts := protocol.NewServerOptions(opts...)
 
        return func(srvOpts *ServerOptions) {
                if srvOpts.Protocols == nil {
@@ -852,8 +852,8 @@ func WithTag(tag string) ServiceOption {
        }
 }
 
-func WithProtocol(opts ...protocol.Option) ServiceOption {
-       proOpts := protocol.NewOptions(opts...)
+func WithProtocol(opts ...protocol.ServerOption) ServiceOption {
+       proOpts := protocol.NewServerOptions(opts...)
 
        return func(opts *ServiceOptions) {
                if opts.Protocols == nil {

Reply via email to