Unverified Commit 917228c6 authored by Xin.Zh's avatar Xin.Zh Committed by GitHub

Merge pull request #73 from Mulavar/rft/code-format

Rft/code format
parents 1f33b205 ada69206
......@@ -31,6 +31,7 @@ import (
import (
"github.com/dubbogo/gost/sync"
"github.com/montanaflynn/stats"
)
......
......@@ -35,7 +35,9 @@ import (
"github.com/dubbogo/gost/net"
gxsync "github.com/dubbogo/gost/sync"
gxtime "github.com/dubbogo/gost/time"
"github.com/gorilla/websocket"
perrors "github.com/pkg/errors"
)
......@@ -49,13 +51,13 @@ const (
var (
sessionClientKey = "session-client-owner"
connectPingPackage = []byte("connect-ping")
)
/////////////////////////////////////////
// getty tcp client
/////////////////////////////////////////
clientID = EndPointID(0)
)
var clientID = EndPointID(0)
type Client interface {
EndPoint
}
type client struct {
ClientOptions
......@@ -99,17 +101,17 @@ func newClient(t EndPointType, opts ...ClientOption) *client {
return c
}
// NewTcpClient function builds a tcp client.
// NewTCPClient builds a tcp client.
func NewTCPClient(opts ...ClientOption) Client {
return newClient(TCP_CLIENT, opts...)
}
// NewUdpClient function builds a connected udp client
// NewUDPClient builds a connected udp client
func NewUDPClient(opts ...ClientOption) Client {
return newClient(UDP_CLIENT, opts...)
}
// NewWsClient function builds a ws client.
// NewWSClient builds a ws client.
func NewWSClient(opts ...ClientOption) Client {
c := newClient(WS_CLIENT, opts...)
......@@ -184,7 +186,6 @@ func (c *client) dialUDP() Session {
buf []byte
)
// buf = make([]byte, 128)
bufp = gxbytes.GetBytes(128)
defer gxbytes.PutBytes(bufp)
buf = *bufp
......@@ -224,9 +225,7 @@ func (c *client) dialUDP() Session {
<-gxtime.After(connectInterval)
continue
}
// if err == nil {
return newUDPSession(conn, c)
//}
}
}
......
......@@ -29,19 +29,49 @@ import (
import (
"github.com/golang/snappy"
"github.com/gorilla/websocket"
perrors "github.com/pkg/errors"
uatomic "go.uber.org/atomic"
)
var launchTime = time.Now()
var (
launchTime = time.Now()
connID uatomic.Uint32
)
// Connection wrap some connection params and operations
type Connection interface {
ID() uint32
SetCompressType(CompressType)
LocalAddr() string
RemoteAddr() string
incReadPkgNum()
incWritePkgNum()
// UpdateActive update session's active time
UpdateActive()
// GetActive get session's active time
GetActive() time.Time
readTimeout() time.Duration
// SetReadTimeout sets deadline for the future read calls.
SetReadTimeout(time.Duration)
writeTimeout() time.Duration
// SetWriteTimeout sets deadline for the future read calls.
SetWriteTimeout(time.Duration)
send(interface{}) (int, error)
// don't distinguish between tcp connection and websocket connection. Because
// gorilla/websocket/conn.go:(Conn)Close also invoke net.Conn.Close
close(int)
// set related session
setSession(Session)
}
// ///////////////////////////////////////
// getty connection
// ///////////////////////////////////////
var connID uatomic.Uint32
type gettyConn struct {
id uint32
compress CompressType
......@@ -103,7 +133,7 @@ func (c *gettyConn) setSession(ss Session) {
c.ss = ss
}
// Pls do not set read deadline for websocket connection. AlexStocks 20180310
// SetReadTimeout Pls do not set read deadline for websocket connection. AlexStocks 20180310
// gorilla/websocket/conn.go:NextReader will always fail when got a timeout error.
//
// Pls do not set read deadline when using compression. AlexStocks 20180314.
......@@ -122,7 +152,7 @@ func (c gettyConn) writeTimeout() time.Duration {
return c.wTimeout
}
// Pls do not set write deadline for websocket connection. AlexStocks 20180310
// SetWriteTimeout Pls do not set write deadline for websocket connection. AlexStocks 20180310
// gorilla/websocket/conn.go:NextWriter will always fail when got a timeout error.
//
// Pls do not set write deadline when using compression. AlexStocks 20180314.
......@@ -154,7 +184,7 @@ func newGettyTCPConn(conn net.Conn) *gettyTCPConn {
panic("newGettyTCPConn(conn):@conn is nil")
}
var localAddr, peerAddr string
// check conn.LocalAddr or conn.RemoetAddr is nil to defeat panic on 2016/09/27
// check conn.LocalAddr or conn.RemoteAddr is nil to defeat panic on 2016/09/27
if conn.LocalAddr() != nil {
localAddr = conn.LocalAddr().String()
}
......@@ -201,7 +231,7 @@ func (t *writeFlusher) Write(p []byte) (int, error) {
return n, nil
}
// set compress type(tcp: zip/snappy, websocket:zip)
// SetCompressType set compress type(tcp: zip/snappy, websocket:zip)
func (t *gettyTCPConn) SetCompressType(c CompressType) {
switch c {
case CompressNone, CompressZip, CompressBestSpeed, CompressBestCompression, CompressHuffman:
......@@ -505,7 +535,7 @@ func newGettyWSConn(conn *websocket.Conn) *gettyWSConn {
return gettyWSConn
}
// set compress type
// SetCompressType set compress type
func (w *gettyWSConn) SetCompressType(c CompressType) {
switch c {
case CompressNone, CompressZip, CompressBestSpeed, CompressBestCompression, CompressHuffman:
......
......@@ -18,6 +18,7 @@
package getty
import (
"compress/flate"
"strconv"
)
......@@ -67,3 +68,14 @@ func (x EndPointType) String() string {
return strconv.Itoa(int(x))
}
type CompressType int
const (
CompressNone CompressType = flate.NoCompression // 0
CompressZip = flate.DefaultCompression // -1
CompressBestSpeed = flate.BestSpeed // 1
CompressBestCompression = flate.BestCompression // 9
CompressHuffman = flate.HuffmanOnly // -2
CompressSnappy = 10
)
......@@ -18,16 +18,17 @@
package getty
import (
"compress/flate"
"net"
"time"
)
import (
gxsync "github.com/dubbogo/gost/sync"
perrors "github.com/pkg/errors"
)
var (
ErrSessionClosed = perrors.New("session Already Closed")
ErrSessionBlocked = perrors.New("session Full Blocked")
ErrNullPeerAddr = perrors.New("peer address is nil")
)
// NewSessionCallback will be invoked when server accepts a new client connection or client connects to server successfully.
// If there are too many client connections or u do not want to connect a server again, u can return non-nil error. And
// then getty will close the new session.
......@@ -35,7 +36,7 @@ type NewSessionCallback func(Session) error
// Reader is used to unmarshal a complete pkg from buffer
type Reader interface {
// Parse tcp/udp/websocket pkg from buffer and if possible return a complete pkg.
// Read Parse tcp/udp/websocket pkg from buffer and if possible return a complete pkg.
// When receiving a tcp network streaming segment, there are 4 cases as following:
// case 1: a error found in the streaming segment;
// case 2: can not unmarshal a pkg header from the streaming segment;
......@@ -53,7 +54,7 @@ type Reader interface {
// Writer is used to marshal pkg and write to session
type Writer interface {
// if @Session is udpGettySession, the second parameter is UDPContext.
// Write if @Session is udpGettySession, the second parameter is UDPContext.
Write(Session, interface{}) ([]byte, error)
}
......@@ -65,20 +66,20 @@ type ReadWriter interface {
// EventListener is used to process pkg that received from remote session
type EventListener interface {
// invoked when session opened
// OnOpen invoked when session opened
// If the return error is not nil, @Session will be closed.
OnOpen(Session) error
// invoked when session closed.
// OnClose invoked when session closed.
OnClose(Session)
// invoked when got error.
// OnError invoked when got error.
OnError(Session, error)
// invoked periodically, its period can be set by (Session)SetCronPeriod
// OnCron invoked periodically, its period can be set by (Session)SetCronPeriod
OnCron(Session)
// invoked when getty received a package. Pls attention that do not handle long time
// OnMessage invoked when getty received a package. Pls attention that do not handle long time
// logic processing in this func. You'd better set the package's maximum length.
// If the message's length is greater than it, u should should return err in
// Reader{Read} and getty will close this connection soon.
......@@ -92,131 +93,18 @@ type EventListener interface {
OnMessage(Session, interface{})
}
/////////////////////////////////////////
// compress
/////////////////////////////////////////
type CompressType int
const (
CompressNone CompressType = flate.NoCompression // 0
CompressZip = flate.DefaultCompression // -1
CompressBestSpeed = flate.BestSpeed // 1
CompressBestCompression = flate.BestCompression // 9
CompressHuffman = flate.HuffmanOnly // -2
CompressSnappy = 10
)
/////////////////////////////////////////
// connection
/////////////////////////////////////////
type Connection interface {
ID() uint32
SetCompressType(CompressType)
LocalAddr() string
RemoteAddr() string
incReadPkgNum()
incWritePkgNum()
// update session's active time
UpdateActive()
// get session's active time
GetActive() time.Time
readTimeout() time.Duration
// SetReadTimeout sets deadline for the future read calls.
SetReadTimeout(time.Duration)
writeTimeout() time.Duration
// SetWriteTimeout sets deadline for the future read calls.
SetWriteTimeout(time.Duration)
send(interface{}) (int, error)
// don't distinguish between tcp connection and websocket connection. Because
// gorilla/websocket/conn.go:(Conn)Close also invoke net.Conn.Close
close(int)
// set related session
setSession(Session)
}
/////////////////////////////////////////
// Session
/////////////////////////////////////////
var (
ErrSessionClosed = perrors.New("session Already Closed")
ErrSessionBlocked = perrors.New("session Full Blocked")
ErrNullPeerAddr = perrors.New("peer address is nil")
)
type Session interface {
Connection
Reset()
Conn() net.Conn
Stat() string
IsClosed() bool
// get endpoint type
EndPoint() EndPoint
SetMaxMsgLen(int)
SetName(string)
SetEventListener(EventListener)
SetPkgHandler(ReadWriter)
SetReader(Reader)
SetWriter(Writer)
SetCronPeriod(int)
SetWaitTime(time.Duration)
GetAttribute(interface{}) interface{}
SetAttribute(interface{}, interface{})
RemoveAttribute(interface{})
// the Writer will invoke this function. Pls attention that if timeout is less than 0, WritePkg will send @pkg asap.
// for udp session, the first parameter should be UDPContext.
// totalBytesLength: @pkg stream bytes length after encoding @pkg.
// sendBytesLength: stream bytes length that sent out successfully.
// err: maybe it has illegal data, encoding error, or write out system error.
WritePkg(pkg interface{}, timeout time.Duration) (totalBytesLength int, sendBytesLength int, err error)
WriteBytes([]byte) (int, error)
WriteBytesArray(...[]byte) (int, error)
Close()
}
/////////////////////////////////////////
// EndPoint
/////////////////////////////////////////
// EndPoint represents the identity of the client/server
type EndPoint interface {
// get EndPoint ID
// ID get EndPoint ID
ID() EndPointID
// get endpoint type
// EndPointType get endpoint type
EndPointType() EndPointType
// run event loop and serves client request.
// RunEventLoop run event loop and serves client request.
RunEventLoop(newSession NewSessionCallback)
// check the endpoint has been closed
// IsClosed check the endpoint has been closed
IsClosed() bool
// close the endpoint and free its resource
// Close close the endpoint and free its resource
Close()
// GetTaskPool get task pool implemented by dubbogo/gost
GetTaskPool() gxsync.GenericTaskPool
}
type Client interface {
EndPoint
}
// Server interface
type Server interface {
EndPoint
}
// StreamServer is like tcp/websocket/wss server
type StreamServer interface {
Server
// get the network listener
Listener() net.Listener
}
// PacketServer is like udp listen endpoint
type PacketServer interface {
Server
// get the network listener
PacketConn() net.PacketConn
}
......@@ -97,7 +97,7 @@ func init() {
// }()
}
// SetLogger: customize yourself logger.
// SetLogger customize yourself logger.
func SetLogger(logger Logger) {
log = logger
}
......@@ -107,7 +107,7 @@ func GetLogger() Logger {
return log
}
// SetLoggerLevel
// SetLoggerLevel set logger level
func SetLoggerLevel(level LoggerLevel) error {
var err error
zapLoggerConfig.Level = zap.NewAtomicLevelAt(zapcore.Level(level))
......@@ -119,7 +119,7 @@ func SetLoggerLevel(level LoggerLevel) error {
return nil
}
// SetLoggerCallerDisable: disable caller info in production env for performance improve.
// SetLoggerCallerDisable disable caller info in production env for performance improve.
// It is highly recommended that you execute this method in a production environment.
func SetLoggerCallerDisable() error {
var err error
......
......@@ -37,56 +37,56 @@ type ServerOptions struct {
tPool gxsync.GenericTaskPool
}
// @addr server listen address.
// WithLocalAddress @addr server listen address.
func WithLocalAddress(addr string) ServerOption {
return func(o *ServerOptions) {
o.addr = addr
}
}
// @path: websocket request url path
// WithWebsocketServerPath @path: websocket request url path
func WithWebsocketServerPath(path string) ServerOption {
return func(o *ServerOptions) {
o.path = path
}
}
// @cert: server certificate file
// WithWebsocketServerCert @cert: server certificate file
func WithWebsocketServerCert(cert string) ServerOption {
return func(o *ServerOptions) {
o.cert = cert
}
}
// @key: server private key(contains its public key)
// WithWebsocketServerPrivateKey @key: server private key(contains its public key)
func WithWebsocketServerPrivateKey(key string) ServerOption {
return func(o *ServerOptions) {
o.privateKey = key
}
}
// @cert is the root certificate file to verify the legitimacy of server
// WithWebsocketServerRootCert @cert is the root certificate file to verify the legitimacy of server
func WithWebsocketServerRootCert(cert string) ServerOption {
return func(o *ServerOptions) {
o.caCert = cert
}
}
// @pool server task pool.
// WithServerTaskPool @pool server task pool.
func WithServerTaskPool(pool gxsync.GenericTaskPool) ServerOption {
return func(o *ServerOptions) {
o.tPool = pool
}
}
// @WithSslEnabled enable use tls
// WithServerSslEnabled enable use tls
func WithServerSslEnabled(sslEnabled bool) ServerOption {
return func(o *ServerOptions) {
o.sslEnabled = sslEnabled
}
}
// @WithServerKeyCertChainPath sslConfig is tls config
// WithServerTlsConfigBuilder sslConfig is tls config
func WithServerTlsConfigBuilder(tlsConfigBuilder TlsConfigBuilder) ServerOption {
return func(o *ServerOptions) {
o.tlsConfigBuilder = tlsConfigBuilder
......@@ -116,14 +116,14 @@ type ClientOptions struct {
tPool gxsync.GenericTaskPool
}
// @addr is server address.
// WithServerAddress @addr is server address.
func WithServerAddress(addr string) ClientOption {
return func(o *ClientOptions) {
o.addr = addr
}
}
// @reconnectInterval is server address.
// WithReconnectInterval @reconnectInterval is server address.
func WithReconnectInterval(reconnectInterval int) ClientOption {
return func(o *ClientOptions) {
if 0 < reconnectInterval {
......@@ -132,14 +132,14 @@ func WithReconnectInterval(reconnectInterval int) ClientOption {
}
}
// @pool client task pool.
// WithClientTaskPool @pool client task pool.
func WithClientTaskPool(pool gxsync.GenericTaskPool) ClientOption {
return func(o *ClientOptions) {
o.tPool = pool
}
}
// @num is connection number.
// WithConnectionNumber @num is connection number.
func WithConnectionNumber(num int) ClientOption {
return func(o *ClientOptions) {
if 0 < num {
......@@ -148,21 +148,21 @@ func WithConnectionNumber(num int) ClientOption {
}
}
// @certs is client certificate file. it can be empty.
// WithRootCertificateFile @certs is client certificate file. it can be empty.
func WithRootCertificateFile(cert string) ClientOption {
return func(o *ClientOptions) {
o.cert = cert
}
}
// @WithSslEnabled enable use tls
// WithClientSslEnabled enable use tls
func WithClientSslEnabled(sslEnabled bool) ClientOption {
return func(o *ClientOptions) {
o.sslEnabled = sslEnabled
}
}
// @WithClientKeyCertChainPath sslConfig is tls config
// WithClientTlsConfigBuilder sslConfig is tls config
func WithClientTlsConfigBuilder(tlsConfigBuilder TlsConfigBuilder) ClientOption {
return func(o *ClientOptions) {
o.tlsConfigBuilder = tlsConfigBuilder
......
......@@ -34,8 +34,11 @@ import (
gxnet "github.com/dubbogo/gost/net"
gxsync "github.com/dubbogo/gost/sync"
gxtime "github.com/dubbogo/gost/time"
"github.com/gorilla/websocket"
perrors "github.com/pkg/errors"
uatomic "go.uber.org/atomic"
)
......@@ -46,6 +49,25 @@ var (
serverID uatomic.Int32
)
// Server interface
type Server interface {
EndPoint
}
// StreamServer is like tcp/websocket/wss server
type StreamServer interface {
Server
// Listener get the network listener
Listener() net.Listener
}
// PacketServer is like udp listen endpoint
type PacketServer interface {
Server
// PacketConn get the network listener
PacketConn() net.PacketConn
}
type server struct {
ServerOptions
......@@ -87,7 +109,7 @@ func NewTCPServer(opts ...ServerOption) Server {
}
// NewUDPEndPoint builds a unconnected udp server.
func NewUDPPEndPoint(opts ...ServerOption) Server {
func NewUDPEndPoint(opts ...ServerOption) Server {
return newServer(UDP_ENDPOINT, opts...)
}
......@@ -255,7 +277,7 @@ func (s *server) accept(newSession NewSessionCallback) (Session, error) {
return ss, nil
}
func (s *server) runTcpEventLoop(newSession NewSessionCallback) {
func (s *server) runTCPEventLoop(newSession NewSessionCallback) {
s.wg.Add(1)
go func() {
defer s.wg.Done()
......@@ -469,7 +491,7 @@ func (s *server) RunEventLoop(newSession NewSessionCallback) {
switch s.endPointType {
case TCP_SERVER:
s.runTcpEventLoop(newSession)
s.runTCPEventLoop(newSession)
case UDP_ENDPOINT:
s.runUDPEventLoop(newSession)
case WS_SERVER:
......
......@@ -32,8 +32,11 @@ import (
gxbytes "github.com/dubbogo/gost/bytes"
gxcontext "github.com/dubbogo/gost/context"
gxtime "github.com/dubbogo/gost/time"
"github.com/gorilla/websocket"
perrors "github.com/pkg/errors"
uatomic "go.uber.org/atomic"
)
......@@ -53,10 +56,6 @@ const (
outputFormat = "session %s, Read Bytes: %d, Write Bytes: %d, Read Pkgs: %d, Write Pkgs: %d"
)
/////////////////////////////////////////
// session
/////////////////////////////////////////
var defaultTimerWheel *gxtime.TimerWheel
func init() {
......@@ -64,6 +63,41 @@ func init() {
defaultTimerWheel = gxtime.GetDefaultTimerWheel()
}
// Session wrap connection between the server and the client
type Session interface {
Connection
Reset()
Conn() net.Conn
Stat() string
IsClosed() bool
// EndPoint get endpoint type
EndPoint() EndPoint
SetMaxMsgLen(int)
SetName(string)
SetEventListener(EventListener)
SetPkgHandler(ReadWriter)
SetReader(Reader)
SetWriter(Writer)
SetCronPeriod(int)
SetWaitTime(time.Duration)
GetAttribute(interface{}) interface{}
SetAttribute(interface{}, interface{})
RemoveAttribute(interface{})
// WritePkg the Writer will invoke this function. Pls attention that if timeout is less than 0, WritePkg will send @pkg asap.
// for udp session, the first parameter should be UDPContext.
// totalBytesLength: @pkg stream bytes length after encoding @pkg.
// sendBytesLength: stream bytes length that sent out successfully.
// err: maybe it has illegal data, encoding error, or write out system error.
WritePkg(pkg interface{}, timeout time.Duration) (totalBytesLength int, sendBytesLength int, err error)
WriteBytes([]byte) (int, error)
WriteBytesArray(...[]byte) (int, error)
Close()
}
// getty base session
type session struct {
name string
......@@ -156,7 +190,6 @@ func (s *session) Reset() {
}
}
// func (s *session) SetConn(conn net.Conn) { s.gettyConn = newGettyConn(conn) }
func (s *session) Conn() net.Conn {
if tc, ok := s.Connection.(*gettyTCPConn); ok {
return tc.conn
......@@ -193,7 +226,7 @@ func (s *session) gettyConn() *gettyConn {
return nil
}
// return the connect statistic data
// Stat get the connect statistic data
func (s *session) Stat() string {
var conn *gettyConn
if conn = s.gettyConn(); conn == nil {
......@@ -209,7 +242,7 @@ func (s *session) Stat() string {
)
}
// check whether the session has been closed.
// IsClosed check whether the session has been closed.
func (s *session) IsClosed() bool {
select {
case <-s.done:
......@@ -220,7 +253,7 @@ func (s *session) IsClosed() bool {
}
}
// set maximum package length of every package in (EventListener)OnMessage(@pkgs)
// SetMaxMsgLen set maximum package length of every package in (EventListener)OnMessage(@pkgs)
func (s *session) SetMaxMsgLen(length int) {
s.lock.Lock()
defer s.lock.Unlock()
......@@ -228,7 +261,7 @@ func (s *session) SetMaxMsgLen(length int) {
s.maxMsgLen = int32(length)
}
// set session name
// SetName set session name
func (s *session) SetName(name string) {
s.lock.Lock()
defer s.lock.Unlock()
......@@ -236,7 +269,7 @@ func (s *session) SetName(name string) {
s.name = name
}
// set EventListener
// SetEventListener set event listener
func (s *session) SetEventListener(listener EventListener) {
s.lock.Lock()
defer s.lock.Unlock()
......@@ -244,7 +277,7 @@ func (s *session) SetEventListener(listener EventListener) {
s.listener = listener
}
// set package handler
// SetPkgHandler set package handler
func (s *session) SetPkgHandler(handler ReadWriter) {
s.lock.Lock()
defer s.lock.Unlock()
......@@ -253,7 +286,6 @@ func (s *session) SetPkgHandler(handler ReadWriter) {
s.writer = handler
}
// set Reader
func (s *session) SetReader(reader Reader) {
s.lock.Lock()
defer s.lock.Unlock()
......@@ -261,7 +293,6 @@ func (s *session) SetReader(reader Reader) {
s.reader = reader
}
// set Writer
func (s *session) SetWriter(writer Writer) {
s.lock.Lock()
defer s.lock.Unlock()
......@@ -269,7 +300,7 @@ func (s *session) SetWriter(writer Writer) {
s.writer = writer
}
// period is in millisecond. Websocket session will send ping frame automatically every peroid.
// SetCronPeriod period is in millisecond. Websocket session will send ping frame automatically every peroid.
func (s *session) SetCronPeriod(period int) {
if period < 1 {
panic("@period < 1")
......@@ -280,7 +311,7 @@ func (s *session) SetCronPeriod(period int) {
s.period = time.Duration(period) * time.Millisecond
}
// set maximum wait time when session got error or got exit signal
// SetWaitTime set maximum wait time when session got error or got exit signal
func (s *session) SetWaitTime(waitTime time.Duration) {
if waitTime < 1 {
panic("@wait < 1")
......@@ -291,7 +322,7 @@ func (s *session) SetWaitTime(waitTime time.Duration) {
s.wait = waitTime
}
// set attribute of key @session:key
// GetAttribute get attribute of key @session:key
func (s *session) GetAttribute(key interface{}) interface{} {
s.lock.RLock()
if s.attrs == nil {
......@@ -308,7 +339,7 @@ func (s *session) GetAttribute(key interface{}) interface{} {
return ret
}
// get attribute of key @session:key
// SetAttribute set attribute of key @session:key
func (s *session) SetAttribute(key interface{}, value interface{}) {
s.lock.Lock()
if s.attrs != nil {
......@@ -317,7 +348,7 @@ func (s *session) SetAttribute(key interface{}, value interface{}) {
s.lock.Unlock()
}
// delete attribute of key @session:key
// RemoveAttribute remove attribute of key @session:key
func (s *session) RemoveAttribute(key interface{}) {
s.lock.Lock()
if s.attrs != nil {
......@@ -381,7 +412,7 @@ func (s *session) WritePkg(pkg interface{}, timeout time.Duration) (int, int, er
return len(pkgBytes), succssCount, nil
}
// for codecs
// WriteBytes for codecs
func (s *session) WriteBytes(pkg []byte) (int, error) {
if s.IsClosed() {
return 0, ErrSessionClosed
......@@ -394,7 +425,7 @@ func (s *session) WriteBytes(pkg []byte) (int, error) {
return lg, nil
}
// Write multiple packages at once. so we invoke write sys.call just one time.
// WriteBytesArray Write multiple packages at once. so we invoke write sys.call just one time.
func (s *session) WriteBytesArray(pkgs ...[]byte) (int, error) {
if s.IsClosed() {
return 0, ErrSessionClosed
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment