//处理连接请求 func (this *server) handlerConnection(conn *net.TCPConn) { defer logger.CatchException() logger.Infof("New connection coming ... IP=%s ", conn.RemoteAddr()) conn.SetNoDelay(true) //无延迟 conn.SetKeepAlive(true) //保持激活 conn.SetReadBuffer(64 * 1024) //设置读缓冲区大小 conn.SetWriteBuffer(64 * 1024) //设置写缓冲区大小 conn.SetReadDeadline(time.Now().Add(30000000 * time.Second)) //设置读超时 session := network.NewSession(conn) defer session.Close() for { msg, err := session.RecvMSG() if err != nil { logger.Infof("RecvMsgs IP=%s err=%v", conn.RemoteAddr(), err.Error()) return } ret := this.ProcessMessage(session, msg) if ret == false { return } } }
// Accept accepts connections on the listener and serves requests // for each incoming connection. Accept blocks; the caller typically // invokes it in a go statement. func acceptTCP(server *Server, lis *net.TCPListener) { var ( conn *net.TCPConn err error r int ) for { if conn, err = lis.AcceptTCP(); err != nil { // if listener close then return log.Error("listener.Accept(\"%s\") error(%v)", lis.Addr().String(), err) return } if err = conn.SetKeepAlive(Conf.TCPKeepalive); err != nil { log.Error("conn.SetKeepAlive() error(%v)", err) return } if err = conn.SetReadBuffer(Conf.TCPSndbuf); err != nil { log.Error("conn.SetReadBuffer() error(%v)", err) return } if err = conn.SetWriteBuffer(Conf.TCPRcvbuf); err != nil { log.Error("conn.SetWriteBuffer() error(%v)", err) return } go serveTCP(server, conn, r) if r++; r == maxInt { r = 0 } } }
// NewConn creates a new connection for the sio. It generates the session id and // prepares the internal structure for usage. func newConn(serv *Server, fd uint32, nc *net.TCPConn) (c *Conn, err error) { host, _, err := net.SplitHostPort(nc.RemoteAddr().String()) if err != nil { serv.Log("mudoo/newConn: GetRemoteAddr:", err) return } c = &Conn{ serv: serv, fd: fd, nc: nc, raddr: host, online: true, lastConnected: time.Now().UnixNano(), wakeupFlusher: make(chan byte), wakeupReader: make(chan byte), numConns: 0, numHeartbeats: 0, decBuf: new(Buffer), } nc.SetReadBuffer(serv.config.ReadBufferSize) nc.SetWriteBuffer(serv.config.WriteBufferSize) go c.keepalive() // go c.flusher() go c.reader() return }
// Accept accepts connections on the listener and serves requests // for each incoming connection. Accept blocks; the caller typically // invokes it in a go statement. func (server *Server) AcceptTCP(lis *net.TCPListener, i int) { var ( conn *net.TCPConn err error ) for { log.Debug("server: accept round: %d", i) if conn, err = lis.AcceptTCP(); err != nil { // if listener close then return log.Error("listener.Accept(\"%s\") error(%v)", lis.Addr().String(), err) return } if err = conn.SetKeepAlive(Conf.TCPKeepalive); err != nil { log.Error("conn.SetKeepAlive() error(%v)", err) return } if err = conn.SetReadBuffer(Conf.TCPSndbuf); err != nil { log.Error("conn.SetReadBuffer() error(%v)", err) return } if err = conn.SetWriteBuffer(Conf.TCPRcvbuf); err != nil { log.Error("conn.SetWriteBuffer() error(%v)", err) return } go server.serveConn(conn, i) if i++; i == maxInt { i = 0 } } }
func (server *TcpServer) Start() (err error) { for { var conn *net.TCPConn if conn, err = server.TCPListener.AcceptTCP(); err != nil { return err } if server.keepAlive != nil { if err := conn.SetKeepAlive(server.keepAlive.(bool)); err != nil { return err } } if server.keepAlivePeriod != nil { if kap, ok := (net.Conn(conn)).(iKeepAlivePeriod); ok { if err := kap.SetKeepAlivePeriod(server.keepAlivePeriod.(time.Duration)); err != nil { return err } } } if server.linger != nil { if err := conn.SetLinger(server.linger.(int)); err != nil { return err } } if server.noDelay != nil { if err := conn.SetNoDelay(server.noDelay.(bool)); err != nil { return err } } if server.readBuffer != nil { if err := conn.SetReadBuffer(server.readBuffer.(int)); err != nil { return err } } if server.writerBuffer != nil { if err := conn.SetWriteBuffer(server.writerBuffer.(int)); err != nil { return err } } if server.deadline != nil { if err := conn.SetDeadline(server.deadline.(time.Time)); err != nil { return err } } if server.readDeadline != nil { if err := conn.SetReadDeadline(server.readDeadline.(time.Time)); err != nil { return err } } if server.writerDeadline != nil { if err := conn.SetWriteDeadline(server.writerDeadline.(time.Time)); err != nil { return err } } if server.config != nil { server.ServeTCP(tls.Client(conn, server.config)) } else { server.ServeTCP(conn) } } }
func configureConn (conn *net.TCPConn, spec *ConnectionSpec) { // these two -- the most important -- are causing problems on my osx/64 // where a "service unavailable" pops up in the async reads // but we absolutely need to be able to use timeouts. // conn.SetReadTimeout(spec.rTimeout); // conn.SetWriteTimeout(spec.wTimeout); conn.SetLinger(spec.lingerspec); conn.SetKeepAlive(spec.keepalive); conn.SetReadBuffer(spec.rBufSize); conn.SetWriteBuffer(spec.wBufSize); }
func TCPConnWrite(c *net.TCPConn) error { c.SetWriteBuffer(*packetsize) for { _, err := c.Write(b) if err != nil { if err == io.EOF { log.Println("Client ", c.RemoteAddr(), " disconnected") c.Close() return nil } else { log.Println("Failed writing bytes to conn: ", c, " with error ", err) c.Close() return err } } } return nil }
func handleConnection(conn *net.TCPConn) { defer conn.Close() defer func() { if err := recover(); err != nil { fmt.Println(err) return } }() conn.SetKeepAlive(true) conn.SetReadBuffer(4096) conn.SetWriteBuffer(4096) handler := NewHandler(conn) accu := lendecoder.NewAccumulator(handler, 2, 1200) err := accu.ReadFrom(conn) if err != nil { fmt.Printf("Error: %v\n", err) } }
func NewSession(conn *net.TCPConn, rc *turbo.RemotingConfig) *Session { conn.SetKeepAlive(true) conn.SetKeepAlivePeriod(rc.IdleTime * 2) //禁用nagle conn.SetNoDelay(true) conn.SetReadBuffer(rc.ReadBufferSize) conn.SetWriteBuffer(rc.WriteBufferSize) session := &Session{ conn: conn, br: bufio.NewReaderSize(conn, rc.ReadBufferSize), bw: bufio.NewWriterSize(conn, rc.WriteBufferSize), ReadChannel: make(chan *packet.Packet, rc.ReadChannelSize), WriteChannel: make(chan *packet.Packet, rc.WriteChannelSize), isClose: false, remoteAddr: conn.RemoteAddr().String(), rc: rc} return session }
// ServeTCP ... func (service *TcpService) ServeTCP(conn *net.TCPConn) (err error) { if service.keepAlive != nil { if err = conn.SetKeepAlive(service.keepAlive.(bool)); err != nil { return err } } if service.keepAlivePeriod != nil { if kap, ok := (net.Conn(conn)).(iKeepAlivePeriod); ok { if err = kap.SetKeepAlivePeriod(service.keepAlivePeriod.(time.Duration)); err != nil { return err } } } if service.linger != nil { if err = conn.SetLinger(service.linger.(int)); err != nil { return err } } if service.noDelay != nil { if err = conn.SetNoDelay(service.noDelay.(bool)); err != nil { return err } } if service.readBuffer != nil { if err = conn.SetReadBuffer(service.readBuffer.(int)); err != nil { return err } } if service.writeBuffer != nil { if err = conn.SetWriteBuffer(service.writeBuffer.(int)); err != nil { return err } } if service.config != nil { tlsConn := tls.Server(conn, service.config) tlsConn.Handshake() return service.Serve(tlsConn) } return service.Serve(conn) }
// start a goroutine when a new connection is accepted func handleClient(conn *net.TCPConn) { defer utils.PrintPanicStack() // set per-connection socket buffer conn.SetReadBuffer(SO_RCVBUF) // set initial socket buffer conn.SetWriteBuffer(SO_SNDBUF) // initial network control struct header := make([]byte, 2) in := make(chan []byte) defer func() { close(in) // session will close }() // create a new session object for the connection var sess Session host, port, err := net.SplitHostPort(conn.RemoteAddr().String()) if err != nil { log.Error("cannot get remote address:", err) return } sess.IP = net.ParseIP(host) log.Infof("new connection from:%v port:%v", host, port) // session die signal sess.Die = make(chan struct{}) // create a write buffer out := new_buffer(conn, sess.Die) go out.start() // start one agent for handling packet wg.Add(1) go agent(&sess, in, out) // network loop for { // solve dead link problem conn.SetReadDeadline(time.Now().Add(TCP_READ_DEADLINE * time.Second)) n, err := io.ReadFull(conn, header) if err != nil { log.Warningf("read header failed, ip:%v reason:%v size:%v", sess.IP, err, n) return } size := binary.BigEndian.Uint16(header) // alloc a byte slice for reading payload := make([]byte, size) // read msg n, err = io.ReadFull(conn, payload) if err != nil { log.Warningf("read payload failed, ip:%v reason:%v size:%v", sess.IP, err, n) return } select { case in <- payload: // payload queued case <-sess.Die: log.Warningf("connection closed by logic, flag:%v ip:%v", sess.Flag, sess.IP) return } } }
func (service *TcpService) ServeTCP(conn *net.TCPConn) (err error) { if service.keepAlive != nil { if err = conn.SetKeepAlive(service.keepAlive.(bool)); err != nil { return err } } if service.keepAlivePeriod != nil { if kap, ok := (net.Conn(conn)).(iKeepAlivePeriod); ok { if err = kap.SetKeepAlivePeriod(service.keepAlivePeriod.(time.Duration)); err != nil { return err } } } if service.linger != nil { if err = conn.SetLinger(service.linger.(int)); err != nil { return err } } if service.noDelay != nil { if err = conn.SetNoDelay(service.noDelay.(bool)); err != nil { return err } } if service.readBuffer != nil { if err = conn.SetReadBuffer(service.readBuffer.(int)); err != nil { return err } } if service.writeBuffer != nil { if err = conn.SetWriteBuffer(service.writeBuffer.(int)); err != nil { return err } } if service.timeout != nil { if err = conn.SetDeadline(time.Now().Add(service.timeout.(time.Duration))); err != nil { return err } } go func(conn net.Conn) { if service.config != nil { tlsConn := tls.Server(conn, service.config) tlsConn.Handshake() conn = tlsConn } var data []byte var err error for { if service.readTimeout != nil { err = conn.SetReadDeadline(time.Now().Add(service.readTimeout.(time.Duration))) } if err == nil { data, err = receiveDataOverTcp(conn) } if err == nil { data = service.Handle(data, conn) if service.writeTimeout != nil { err = conn.SetWriteDeadline(time.Now().Add(service.writeTimeout.(time.Duration))) } if err == nil { err = sendDataOverTcp(conn, data) } } if err != nil { conn.Close() break } } }(conn) return nil }
// start a goroutine when a new connection is accepted func handleClient(conn *net.TCPConn) { defer utils.PrintPanicStack() // set per-connection socket buffer //设置conn连接接受缓存的大小, 当超过缓存时, 会进入阻塞状态,等待被读取 conn.SetReadBuffer(SO_RCVBUF) // set initial socket buffer //设置conn连接发送缓存的大小, 当超过缓存时, 会进入阻塞状态,等待被发送成功 conn.SetWriteBuffer(SO_SNDBUF) // initial network control struct // 初始化2个字节数组, 用于存储header长度, 既后面要读取的文件长度 header := make([]byte, 2) // 输入流通道, 解析后的数据将放入,等待被处理 in := make(chan []byte) //设置延迟函数,当玩家断开连接时, 函数退出之前,关闭输入流 defer func() { close(in) // session will close }() // create a new session object for the connection //创建session对象, 用于封装客户端和服务器的信息交换 var sess Session host, port, err := net.SplitHostPort(conn.RemoteAddr().String()) if err != nil { log.Error("cannot get remote address:", err) return } //存储用户ip sess.IP = net.ParseIP(host) //打印用户的ip和端口, 用户可能会双开? log.Infof("new connection from:%v port:%v", host, port) // session die signal sess_die := make(chan bool) //SESSION_DIE 监控有问题................. // create a write buffer // 创建写入buffer对象 out := new_buffer(conn, sess_die) go out.start() // start one agent for handling packet //记录goroutine个数,让系统接收到关闭命令后,会阻塞主线程,至少所有agent线程退出,已保证数据落地 wg.Add(1) go agent(&sess, in, out, sess_die) //network loop for { // solve dead line problem // 设置读超时时间, 如果在任意一次执行Read syscall 返回的时候,超过这个时间点, 则算超时 conn.SetReadDeadline(time.Now().Add(TCP_READ_DEADLINE * time.Second)) //先读取2个字节头文件长度 n, err := io.ReadFull(conn, header) if err != nil { log.Warningf("read header failed, ip:%v reason:%v size:%v", sess.IP, err, n) return } //将2个字节数组转成int16类型, 不丢失精度 size := binary.BigEndian.Uint16(header) // alloc a byte slice for reading // 创建一个指定长度的切片,用于存放具体内容 payload := make([]byte, size) //read msg n, err = io.ReadFull(conn, payload) if err != nil { log.Warningf("read payload failed, ip:%v reason:%v size:%v", sess.IP, err, n) return } select { //接收的数据,转入in通道 case in <- payload: //payload queued //监听sess_die 通道 case <-sess_die: log.Warning("connection closed by logic, flag:%v ip:%v", sess.Flag, sess.IP) return } } // 好像没有处理连接超时, 如果玩家连上游戏后,一直未操作,再次链接时,会是新的连接?难道客户端在许久没有操作的情况下,先发一次ping, 如果有响应,继续操作,如果没响应,则执行重连? // 如果玩家已经退出了游戏,但是通过非正常途径退出的,这时,服务器还保留着该session, 当玩家再次登陆时, 原先的连接何时删除 }
func (server *TcpServer) handle() (err error) { defer func() { if e := recover(); e != nil && err == nil { err = fmt.Errorf("%v", e) } }() if server.listener == nil { return nil } var conn *net.TCPConn if conn, err = server.listener.AcceptTCP(); err != nil { return err } if server.keepAlive != nil { if err = conn.SetKeepAlive(server.keepAlive.(bool)); err != nil { return err } } if server.keepAlivePeriod != nil { if kap, ok := (net.Conn(conn)).(iKeepAlivePeriod); ok { if err = kap.SetKeepAlivePeriod(server.keepAlivePeriod.(time.Duration)); err != nil { return err } } } if server.linger != nil { if err = conn.SetLinger(server.linger.(int)); err != nil { return err } } if server.noDelay != nil { if err = conn.SetNoDelay(server.noDelay.(bool)); err != nil { return err } } if server.readBuffer != nil { if err = conn.SetReadBuffer(server.readBuffer.(int)); err != nil { return err } } if server.writerBuffer != nil { if err = conn.SetWriteBuffer(server.writerBuffer.(int)); err != nil { return err } } if server.deadline != nil { if err = conn.SetDeadline(server.deadline.(time.Time)); err != nil { return err } } if server.readDeadline != nil { if err = conn.SetReadDeadline(server.readDeadline.(time.Time)); err != nil { return err } } if server.writerDeadline != nil { if err = conn.SetWriteDeadline(server.writerDeadline.(time.Time)); err != nil { return err } } if server.config != nil { server.ServeTCP(tls.Client(conn, server.config)) } else { server.ServeTCP(conn) } return nil }
// PIPELINE #1: handleClient // the goroutine is used for reading incoming PACKETS // each packet is defined as : // | 2B size | DATA | // func handleClient(conn *net.TCPConn) { defer utils.PrintPanicStack() // set socket read buffer conn.SetReadBuffer(SO_RCVBUF) // set socket write buffer conn.SetWriteBuffer(SO_SNDBUF) // for reading the 2-Byte header header := make([]byte, 2) // the input channel for agent() in := make(chan []byte) defer func() { close(in) // session will close }() // create a new session object for the connection // and record it's IP address var sess Session host, port, err := net.SplitHostPort(conn.RemoteAddr().String()) if err != nil { log.Error("cannot get remote address:", err) return } sess.IP = net.ParseIP(host) log.Infof("new connection from:%v port:%v", host, port) // session die signal, will be triggered by agent() sess.Die = make(chan struct{}) // create a write buffer out := new_buffer(conn, sess.Die) go out.start() // start agent for PACKET processing wg.Add(1) go agent(&sess, in, out) // read loop for { // solve dead link problem: // physical disconnection without any communcation between client and server // will cause the read to block FOREVER, so a timeout is a rescue. conn.SetReadDeadline(time.Now().Add(TCP_READ_DEADLINE * time.Second)) // read 2B header n, err := io.ReadFull(conn, header) if err != nil { log.Warningf("read header failed, ip:%v reason:%v size:%v", sess.IP, err, n) return } size := binary.BigEndian.Uint16(header) // alloc a byte slice of the size defined in the header for reading data payload := make([]byte, size) n, err = io.ReadFull(conn, payload) if err != nil { log.Warningf("read payload failed, ip:%v reason:%v size:%v", sess.IP, err, n) return } // deliver the data to the input queue of agent() select { case in <- payload: // payload queued case <-sess.Die: log.Warningf("connection closed by logic, flag:%v ip:%v", sess.Flag, sess.IP) return } } }