func (k *Keeper) sendLoop(t *tomb.Tomb) error { var timeout <-chan time.Time = nil for { select { case rep := <-k.sendChan: var buf []byte = k.alloc() defer k.free(buf) bytesWritten, err := EncodePacket(buf[4:], rep) if err != nil { return err } // write frame size binary.BigEndian.PutUint32(buf[:4], uint32(bytesWritten)) // write buffer to connection _, err = k.conn.Write(buf[:4+bytesWritten]) if err != nil { return err } // log output log.Debug("-> ", fmt.Sprintf("%x", buf[:4+bytesWritten])) case <-t.Dying(): // create a timeout in order to send pending requests (close reply) if timeout == nil { timeout = time.After(100 * time.Millisecond) } case <-timeout: close(k.sendChan) return nil } } }
func (k *Keeper) Close() { k.conn.Close() k.tomb.Kill(nil) err := k.tomb.Wait() if err != nil { log.Debug("closed due to: ", err) } }
func (s *Server) Start() { laddr, err := net.ResolveTCPAddr("tcp", s.addr) if nil != err { log.Fatal(err) } listener, err := net.ListenTCP("tcp", laddr) if nil != err { log.Fatal(err) } log.Debug("listening on: ", listener.Addr()) // Make a new service and send it into the background. go s.serve(listener) // Handle SIGINT and SIGTERM. ch := make(chan os.Signal) signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM) log.Debug(<-ch) // Stop the service gracefully. s.Stop() }
func (s *Server) serve(l *net.TCPListener) { defer s.waitGroup.Done() s.waitGroup.Add(1) for { select { case <-s.ch: log.Debug("stopping listening on: ", l.Addr()) l.Close() return default: } l.SetDeadline(time.Now().Add(1e9)) conn, err := l.AcceptTCP() if err != nil { if opErr, ok := err.(*net.OpError); ok && opErr.Timeout() { continue } log.Debug(err) } // handle the connection in a new goroutine. This returns to listener // accepting code so that multiple connections may be served concurrently. keeper := NewKeeper(conn, s.storeClient) go func() { defer s.waitGroup.Done() s.waitGroup.Add(1) log.Debug("client connected: ", conn.RemoteAddr()) if err := keeper.Handle(); err != nil { log.Debug("client disconnected: ", conn.RemoteAddr(), " with error: ", err) } else { log.Debug("client disconnected: ", conn.RemoteAddr()) } }() } }
func (k *Keeper) recvLoop(t *tomb.Tomb) error { for { _, err := k.read(k.temp[:4]) if err != nil { return err } // parse frame size len := binary.BigEndian.Uint32(k.temp[:4]) if len > bufferSize { return errors.New(fmt.Sprintf("length should be at most %d bytes (received %d)", bufferSize, len)) } // alloc buffer (freeing if full read from conn wasn't possible) var buf = k.alloc() defer k.free(buf) // read frame _, err = k.read(buf[:len]) if err != nil { return err } // log input log.Debug("<- ", fmt.Sprintf("%x%x", k.temp[:4], buf[:len])) // send frame to channel select { case k.recvChan <- buf[:len]: case <-t.Dying(): return nil } } return nil }