func (s *Sock) String() string {
	return fmt.Sprintf("%p", s)
}
String returns a name that uniquely identifies the socket during its lifetime
package gotalk
import (
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net"
	"runtime"
	"sync"
	"sync/atomic"
	"time"
)
var (
	ErrUnexpectedStreamingRes = errors.New("unexpected streaming response")
	ErrSockClosed             = errors.New("socket closed")
)
type pendingResMap map[string]chan Response
type pendingReqMap map[string]chan []byte
type Sock struct {
	Handlers *Handlers
	UserData interface{}
	StreamReqLimit int
	CloseHandler func(s *Sock, code int)
	AutoRetryRequests bool
	HeartbeatInterval time.Duration
	OnHeartbeat func(load int, t time.Time)
	connmu    sync.RWMutex        
	conn      io.ReadWriteCloser  
	closex    uint32              
	closeCode int32               
	nextOpID     uint32
	pendingRes   pendingResMap
	pendingResMu sync.RWMutex
	pendingReq   pendingReqMap
	pendingReqMu sync.RWMutex
	shutdownWg *sync.WaitGroup  
}
func NewSock(h *Handlers) *Sock {
	return &Sock{
		Handlers:          h,
		HeartbeatInterval: 20 * time.Second,
	}
}
func Pipe(handlers *Handlers, limits *Limits) (*Sock, *Sock, error) {
	if handlers == nil {
		handlers = DefaultHandlers
	}
	c1, c2 := net.Pipe()
	s1 := NewSock(handlers)
	s2 := NewSock(handlers)
	s1.Adopt(c1)
	s2.Adopt(c2)
	go s1.Read(limits)
	go s2.Read(limits)
	return s1, s2, nil
}
func Connect(how, addr string) (*Sock, error) {
	s := NewSock(DefaultHandlers)
	return s, s.Connect(how, addr, DefaultLimits)
}
func ConnectTLS(how, addr string, config *tls.Config) (*Sock, error) {
	s := NewSock(DefaultHandlers)
	return s, s.ConnectTLS(how, addr, DefaultLimits, config)
}
func (s *Sock) Adopt(r io.ReadWriteCloser) {
	s.connmu.Lock()
	s.conn = r
	atomic.StoreInt32(&s.closeCode, 0)
	atomic.StoreUint32(&s.closex, 0)
	s.connmu.Unlock()
}
func (s *Sock) Connect(how, addr string, limits *Limits) error {
	c, err := net.Dial(how, addr)
	if err != nil {
		return err
	}
	return s.ConnectReader(c, limits)
}
func (s *Sock) ConnectTLS(how, addr string, limits *Limits, config *tls.Config) error {
	if config == nil {
		config = &tls.Config{
			RootCAs: TLSCertPool(),
		}
	} else if config.RootCAs == nil {
		config = config.Clone()
		config.RootCAs = TLSCertPool()
	}
	c, err := tls.Dial(how, addr, config)
	if err != nil {
		return err
	}
	return s.ConnectReader(c, limits)
}
func (s *Sock) ConnectReader(r io.ReadWriteCloser, limits *Limits) error {
	s.Adopt(r)
	if err := s.Handshake(); err != nil {
		return err
	}
	go s.Read(limits)
	return nil
}
func (s *Sock) Conn() io.ReadWriteCloser {
	s.connmu.RLock()
	conn := s.conn
	s.connmu.RUnlock()
	return conn
}