func (c *MsgConnection) Close() error {
	c.wmtx.Lock()
	defer c.wmtx.Unlock()
	err := c.closeUnlocked()
	if err != nil {
		return err
	}
	close(c.stopSending)
	return nil
}
Close closes the connection (implements io.Closer). It is go safe.
package net
import (
	"fmt"
	"io"
	"net"
	"sync"
	"time"
	"github.com/libonomy/libonomy-p2p/crypto"
	"github.com/libonomy/libonomy-p2p/log"
	"github.com/libonomy/libonomy-p2p/p2p/metrics"
	"github.com/libonomy/libonomy-p2p/p2p/p2pcrypto"
)
type MsgConnection struct {
	logger      log.Log
	id          string  
	created     time.Time
	remotePub   p2pcrypto.PublicKey
	remoteAddr  net.Addr
	networker   networker  
	session     NetworkSession
	deadline    time.Duration
	r           io.Reader
	wmtx        sync.Mutex
	w           io.Writer
	closed      bool
	deadliner   deadliner
	messages    chan []byte
	stopSending chan struct{}
	close       io.Closer
	msgSizeLimit int
}
func newMsgConnection(conn readWriteCloseAddresser, netw networker,
	remotePub p2pcrypto.PublicKey, session NetworkSession, msgSizeLimit int, deadline time.Duration, log log.Log) *MsgConnection {
	connection := &MsgConnection{
		logger:       log,
		id:           crypto.UUIDString(),
		created:      time.Now(),
		remotePub:    remotePub,
		remoteAddr:   conn.RemoteAddr(),
		r:            conn,
		w:            conn,
		close:        conn,
		deadline:     deadline,
		deadliner:    conn,
		networker:    netw,
		session:      session,
		messages:     make(chan []byte, MessageQueueSize),
		stopSending:  make(chan struct{}),
		msgSizeLimit: msgSizeLimit,
	}
	go connection.sendListener()
	return connection
}
func (c *MsgConnection) ID() string {
	return c.id
}
func (c *MsgConnection) RemoteAddr() net.Addr {
	return c.remoteAddr
}
func (c *MsgConnection) SetRemotePublicKey(key p2pcrypto.PublicKey) {
	c.remotePub = key
}
func (c *MsgConnection) RemotePublicKey() p2pcrypto.PublicKey {
	return c.remotePub
}
func (c *MsgConnection) SetSession(session NetworkSession) {
	c.session = session
}
func (c *MsgConnection) Session() NetworkSession {
	return c.session
}
func (c *MsgConnection) String() string {
	return c.id
}
func (c *MsgConnection) Created() time.Time {
	return c.created
}
func (c *MsgConnection) publish(message []byte) {
	c.networker.EnqueueMessage(IncomingMessageEvent{c, message})
}
func (c *MsgConnection) sendListener() {
	for {
		select {
		case buf := <-c.messages:
			err := c.SendSock(buf)
			if err != nil {
				log.Error("cannot send message to peer %v", err)
			}
		case <-c.stopSending:
			return
		}
	}
}
func (c *MsgConnection) Send(m []byte) error {
	c.wmtx.Lock()
	if c.closed {
		c.wmtx.Unlock()
		return fmt.Errorf("connection was closed")
	}
	c.wmtx.Unlock()
	c.messages <- m
	return nil
}
func (c *MsgConnection) SendSock(m []byte) error {
	c.wmtx.Lock()
	if c.closed {
		c.wmtx.Unlock()
		return fmt.Errorf("connection was closed")
	}
	err := c.deadliner.SetWriteDeadline(time.Now().Add(c.deadline))
	if err != nil {
		return err
	}
	_, err = c.w.Write(m)
	if err != nil {
		cerr := c.closeUnlocked()
		c.wmtx.Unlock()
		if cerr != ErrAlreadyClosed {
			c.networker.publishClosingConnection(ConnectionWithErr{c, err})  
		}
		return err
	}
	c.wmtx.Unlock()
	metrics.PeerRecv.With(metrics.PeerIDLabel, c.remotePub.String()).Add(float64(len(m)))
	return nil
}
func (c *MsgConnection) closeUnlocked() error {
	if c.closed {
		return ErrAlreadyClosed
	}
	err := c.close.Close()
	c.closed = true
	if err != nil {
		return err
	}
	return nil
}