├── .gitignore ├── LICENSE ├── README.md ├── examples ├── ace │ └── ttcp │ │ └── ttcp.go ├── asio │ └── chat │ │ ├── asio_chat_server │ │ └── main.go │ │ └── server.go ├── simple │ ├── chargen.go │ ├── common.go │ ├── daytime.go │ ├── discard.go │ ├── echo.go │ ├── simple_allinone │ │ └── main.go │ ├── simple_chargen │ │ └── main.go │ ├── simple_chargenclient │ │ └── main.go │ ├── simple_daytime │ │ └── main.go │ ├── simple_discard │ │ └── main.go │ ├── simple_echo │ │ └── main.go │ ├── simple_time │ │ └── main.go │ ├── simple_timeclient │ │ └── main.go │ └── time.go └── socks4a │ └── tcprelay │ └── tcprelay.go └── muduo └── common.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | 24 | *.swp 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Shuo Chen 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, this 11 | list of conditions and the following disclaimer in the documentation and/or 12 | other materials provided with the distribution. 13 | 14 | * The name of the author may not be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 21 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | muduo-examples-in-go 2 | ==================== 3 | -------------------------------------------------------------------------------- /examples/ace/ttcp/ttcp.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/binary" 5 | "flag" 6 | "fmt" 7 | "io" 8 | "net" 9 | "strconv" 10 | "time" 11 | 12 | "github.com/chenshuo/muduo-examples-in-go/muduo" 13 | ) 14 | 15 | type options struct { 16 | port int 17 | length int 18 | number int 19 | transmit bool 20 | receive bool 21 | nodelay bool 22 | host string 23 | } 24 | 25 | var opt options 26 | 27 | type SessionMessage struct { 28 | Number, Length int32 29 | } 30 | 31 | func init() { 32 | flag.IntVar(&opt.port, "p", 5001, "TCP port") 33 | flag.IntVar(&opt.length, "l", 65536, "Buffer length") 34 | flag.IntVar(&opt.number, "n", 8192, "Number of buffers") 35 | flag.BoolVar(&opt.receive, "r", false, "Receive") 36 | flag.StringVar(&opt.host, "t", "", "Transmit") 37 | muduo.Check(binary.Size(SessionMessage{}) == 8, "packed struct") 38 | } 39 | 40 | func transmit() { 41 | sessionMessage := SessionMessage{int32(opt.number), int32(opt.length)} 42 | fmt.Printf("buffer length = %d\nnumber of buffers = %d\n", 43 | sessionMessage.Length, sessionMessage.Number) 44 | total_mb := float64(sessionMessage.Number) * float64(sessionMessage.Length) / 1024.0 / 1024.0 45 | fmt.Printf("%.3f MiB in total\n", total_mb) 46 | 47 | conn, err := net.Dial("tcp", net.JoinHostPort(opt.host, strconv.Itoa(opt.port))) 48 | muduo.PanicOnError(err) 49 | // t := conn.(*net.TCPConn) 50 | // t.SetNoDelay(false) 51 | defer conn.Close() 52 | 53 | start := time.Now() 54 | err = binary.Write(conn, binary.BigEndian, &sessionMessage) 55 | muduo.PanicOnError(err) 56 | 57 | total_len := 4 + opt.length // binary.Size(int32(0)) == 4 58 | // println(total_len) 59 | payload := make([]byte, total_len) 60 | binary.BigEndian.PutUint32(payload, uint32(opt.length)) 61 | for i := 0; i < opt.length; i++ { 62 | payload[4+i] = "0123456789ABCDEF"[i%16] 63 | } 64 | 65 | for i := 0; i < opt.number; i++ { 66 | var n int 67 | n, err = conn.Write(payload) 68 | muduo.PanicOnError(err) 69 | muduo.Check(n == len(payload), "write payload") 70 | 71 | var ack int32 72 | err = binary.Read(conn, binary.BigEndian, &ack) 73 | muduo.PanicOnError(err) 74 | muduo.Check(ack == int32(opt.length), "ack") 75 | } 76 | 77 | elapsed := time.Since(start).Seconds() 78 | fmt.Printf("%.3f seconds\n%.3f MiB/s\n", elapsed, total_mb/elapsed) 79 | } 80 | 81 | func receive() { 82 | listener := muduo.ListenTcpOrDie(fmt.Sprintf(":%d", opt.port)) 83 | defer listener.Close() 84 | println("Accepting", listener.Addr().String()) 85 | conn, err := listener.Accept() 86 | muduo.PanicOnError(err) 87 | defer conn.Close() 88 | 89 | // Read header 90 | var sessionMessage SessionMessage 91 | err = binary.Read(conn, binary.BigEndian, &sessionMessage) 92 | muduo.PanicOnError(err) 93 | 94 | fmt.Printf("receive buffer length = %d\nreceive number of buffers = %d\n", 95 | sessionMessage.Length, sessionMessage.Number) 96 | total_mb := float64(sessionMessage.Number) * float64(sessionMessage.Length) / 1024.0 / 1024.0 97 | fmt.Printf("%.3f MiB in total\n", total_mb) 98 | 99 | payload := make([]byte, sessionMessage.Length) 100 | start := time.Now() 101 | for i := 0; i < int(sessionMessage.Number); i++ { 102 | var length int32 103 | err = binary.Read(conn, binary.BigEndian, &length) 104 | muduo.PanicOnError(err) 105 | muduo.Check(length == sessionMessage.Length, "read length") 106 | 107 | var n int 108 | n, err = io.ReadFull(conn, payload) 109 | muduo.PanicOnError(err) 110 | muduo.Check(n == len(payload), "read payload") 111 | 112 | // ack 113 | err = binary.Write(conn, binary.BigEndian, &length) 114 | muduo.PanicOnError(err) 115 | } 116 | 117 | elapsed := time.Since(start).Seconds() 118 | fmt.Printf("%.3f seconds\n%.3f MiB/s\n", elapsed, total_mb/elapsed) 119 | } 120 | 121 | func main() { 122 | flag.Parse() 123 | opt.transmit = opt.host != "" 124 | if opt.transmit == opt.receive { 125 | println("Either -r or -t must be specified.") 126 | return 127 | } 128 | 129 | if opt.transmit { 130 | transmit() 131 | } else if opt.receive { 132 | receive() 133 | } else { 134 | panic("unknown") 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /examples/asio/chat/asio_chat_server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/chenshuo/muduo-examples-in-go/examples/asio/chat" 7 | ) 8 | 9 | func main() { 10 | log.SetFlags(log.LstdFlags | log.Lmicroseconds | log.Lshortfile) 11 | 12 | server := chat.NewChatServer(":3399") 13 | server.Run() 14 | } 15 | -------------------------------------------------------------------------------- /examples/asio/chat/server.go: -------------------------------------------------------------------------------- 1 | package chat 2 | 3 | import ( 4 | "encoding/binary" 5 | "errors" 6 | "io" 7 | "log" 8 | "net" 9 | "runtime" 10 | "time" 11 | 12 | "github.com/chenshuo/muduo-examples-in-go/muduo" 13 | ) 14 | 15 | type ChatServer struct { 16 | listener net.Listener 17 | conns map[*connection]bool 18 | broadcast chan []byte 19 | register chan *connection 20 | unregister chan *connection 21 | } 22 | 23 | func NewChatServer(listenAddr string) *ChatServer { 24 | return &ChatServer{ 25 | listener: muduo.ListenTcpOrDie(listenAddr), 26 | conns: make(map[*connection]bool), 27 | broadcast: make(chan []byte), // size? 28 | register: make(chan *connection), // size? 29 | unregister: make(chan *connection), // size? 30 | } 31 | } 32 | 33 | type connection struct { 34 | conn net.Conn 35 | // FIXME: use bufio to save syscall 36 | send chan []byte 37 | } 38 | 39 | func (c *connection) input(broadcast chan []byte) { 40 | for { 41 | message, err := c.readMessage() 42 | if err != nil { 43 | log.Println(err) 44 | break 45 | } 46 | broadcast <- message 47 | } 48 | } 49 | 50 | func (c *connection) output() { 51 | defer c.close() 52 | for m := range c.send { 53 | err := binary.Write(c.conn, binary.BigEndian, int32(len(m))) 54 | if err != nil { 55 | log.Println(err) 56 | break 57 | } 58 | var n int 59 | n, err = c.conn.Write(m) 60 | if err != nil { 61 | log.Println(err) 62 | break 63 | } 64 | if n != len(m) { 65 | log.Println("short write") 66 | break 67 | } 68 | } 69 | } 70 | 71 | func (c *connection) close() { 72 | log.Println("close connection") 73 | c.conn.Close() 74 | } 75 | 76 | func (c *connection) readMessage() (message []byte, err error) { 77 | var length int32 78 | err = binary.Read(c.conn, binary.BigEndian, &length) 79 | if err != nil { 80 | return nil, err 81 | } 82 | if length > 65536 || length < 0 { 83 | return nil, errors.New("invalid length") 84 | } 85 | message = make([]byte, int(length)) 86 | if length > 0 { 87 | var n int 88 | n, err = io.ReadFull(c.conn, message) 89 | if err != nil { 90 | return nil, err 91 | } 92 | if n != len(message) { 93 | return message, errors.New("short read") 94 | } 95 | } 96 | return message, nil 97 | } 98 | 99 | func (s *ChatServer) ServeConn(conn net.Conn) { 100 | c := &connection{conn: conn, send: make(chan []byte, 1024)} 101 | s.register <- c 102 | defer func() { s.unregister <- c }() 103 | 104 | go c.output() 105 | c.input(s.broadcast) 106 | } 107 | 108 | func (s *ChatServer) Run() { 109 | ticks := time.Tick(time.Second * 1) 110 | go muduo.ServeTcp(s.listener, s, "chat") 111 | for { 112 | select { 113 | case c := <-s.register: 114 | s.conns[c] = true 115 | case c := <-s.unregister: 116 | delete(s.conns, c) 117 | close(c.send) 118 | case m := <-s.broadcast: 119 | for c := range s.conns { 120 | select { 121 | case c.send <- m: 122 | default: 123 | delete(s.conns, c) 124 | close(c.send) 125 | log.Println("kick slow connection") 126 | } 127 | } 128 | case _ = <-ticks: 129 | log.Println(len(s.conns), runtime.NumGoroutine()) 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /examples/simple/chargen.go: -------------------------------------------------------------------------------- 1 | package simple 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "log" 8 | "net" 9 | "sync/atomic" 10 | "time" 11 | 12 | "github.com/chenshuo/muduo-examples-in-go/muduo" 13 | ) 14 | 15 | type ChargenServer struct { 16 | listener net.Listener 17 | total int64 18 | } 19 | 20 | var message []byte 21 | var repeatReader *RepeatReader 22 | 23 | func NewChargenServer(listenAddr string) *ChargenServer { 24 | server := new(ChargenServer) 25 | server.listener = muduo.ListenTcpOrDie(listenAddr) 26 | return server 27 | } 28 | 29 | func init() { 30 | var buf bytes.Buffer 31 | for i := 33; i < 127; i++ { 32 | buf.WriteByte(byte(i)) 33 | } 34 | l := buf.Len() 35 | n, _ := buf.Write(buf.Bytes()) 36 | if l != n || buf.Len() != 2*l { 37 | panic("buf error") 38 | } 39 | var msg bytes.Buffer 40 | for i := 0; i < 127-33; i++ { 41 | msg.Write(buf.Bytes()[i : i+72]) 42 | msg.WriteByte('\n') 43 | } 44 | message = msg.Bytes() 45 | if len(message) != 94*73 { 46 | panic("short message") 47 | } 48 | repeatReader = NewRepeatReader(message) 49 | } 50 | 51 | func chargen(c net.Conn, total *int64) { 52 | defer c.Close() 53 | for { 54 | n, err := c.Write(message) 55 | atomic.AddInt64(total, int64(n)) 56 | if err != nil { 57 | log.Println("chargen:", err.Error()) 58 | break 59 | } 60 | if n != len(message) { 61 | log.Println("chargen: short write", n, "out of", len(message)) 62 | } 63 | } 64 | printConn(c, "chargen", "DOWN") 65 | } 66 | 67 | func (s *ChargenServer) ServeWithMeter() error { 68 | defer s.listener.Close() 69 | 70 | ticker := time.NewTicker(time.Second) 71 | defer ticker.Stop() 72 | go func() { 73 | start := time.Now() 74 | for t := range ticker.C { 75 | transferred := atomic.SwapInt64(&s.total, int64(0)) 76 | elapsed := t.Sub(start).Seconds() 77 | fmt.Printf("%.3f MiB/s\n", float64(transferred)/elapsed/(1024.0*1024.0)) 78 | start = t 79 | } 80 | }() 81 | 82 | for { 83 | conn, err := s.listener.Accept() 84 | if err != nil { 85 | return err 86 | } 87 | printConn(conn, "chargen", "UP") 88 | go chargen(conn, &s.total) 89 | } 90 | } 91 | 92 | /////////////////// RepeatReader 93 | 94 | type RepeatReader struct { 95 | message []byte 96 | } 97 | 98 | func NewRepeatReader(m []byte) *RepeatReader { 99 | r := new(RepeatReader) 100 | r.message = m 101 | return r 102 | } 103 | 104 | func (r *RepeatReader) Read(p []byte) (n int, err error) { 105 | if len(p) < len(r.message) { 106 | panic("Short read") 107 | } 108 | copy(p, r.message) 109 | return len(r.message), nil 110 | } 111 | 112 | func chargenAdv(c net.Conn) { 113 | defer c.Close() 114 | total, err := io.Copy(c, repeatReader) 115 | if err != nil { 116 | log.Println("chargen:", err.Error()) 117 | } 118 | log.Println("total", total) 119 | printConn(c, "chargen", "DOWN") 120 | } 121 | 122 | func (s *ChargenServer) Serve() error { 123 | return serveTcp(s.listener, chargenAdv, "chargen") 124 | } 125 | -------------------------------------------------------------------------------- /examples/simple/common.go: -------------------------------------------------------------------------------- 1 | package simple 2 | 3 | import ( 4 | "log" 5 | "net" 6 | "time" 7 | ) 8 | 9 | func printConn(c net.Conn, name, updown string) { 10 | log.Printf("%v: %v <- %v is %v\n", 11 | name, c.LocalAddr().String(), c.RemoteAddr().String(), updown) 12 | } 13 | 14 | type ServeTcpConn func(c net.Conn) 15 | 16 | func serveTcp(l net.Listener, f ServeTcpConn, name string) error { 17 | defer l.Close() 18 | var tempDelay time.Duration // how long to sleep on accept failure 19 | for { 20 | conn, err := l.Accept() 21 | if err != nil { 22 | if ne, ok := err.(net.Error); ok && ne.Temporary() { 23 | if tempDelay == 0 { 24 | tempDelay = 5 * time.Millisecond 25 | } else { 26 | tempDelay *= 2 27 | } 28 | if max := 1 * time.Second; tempDelay > max { 29 | tempDelay = max 30 | } 31 | log.Printf("%v: Accept error: %v; retrying in %v", name, err, tempDelay) 32 | time.Sleep(tempDelay) 33 | continue 34 | } 35 | return err 36 | } 37 | tempDelay = 0 38 | printConn(conn, name, "UP") 39 | go f(conn) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /examples/simple/daytime.go: -------------------------------------------------------------------------------- 1 | package simple 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net" 7 | "time" 8 | 9 | "github.com/chenshuo/muduo-examples-in-go/muduo" 10 | ) 11 | 12 | type DaytimeServer struct { 13 | listener net.Listener 14 | } 15 | 16 | func NewDaytimeServer(listenAddr string) *DaytimeServer { 17 | server := new(DaytimeServer) 18 | server.listener = muduo.ListenTcpOrDie(listenAddr) 19 | return server 20 | } 21 | 22 | func (s *DaytimeServer) Serve() { 23 | defer s.listener.Close() 24 | for { 25 | conn, err := s.listener.Accept() 26 | if err == nil { 27 | printConn(conn, "daytime", "UP") 28 | str := fmt.Sprintf("%v\n", time.Now()) 29 | conn.Write([]byte(str)) 30 | printConn(conn, "daytime", "DOWN") 31 | conn.Close() 32 | } else { 33 | log.Println("daytime:", err.Error()) 34 | // TODO: break if ! temporary 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /examples/simple/discard.go: -------------------------------------------------------------------------------- 1 | package simple 2 | 3 | import ( 4 | "io" 5 | "io/ioutil" 6 | "log" 7 | "net" 8 | 9 | "github.com/chenshuo/muduo-examples-in-go/muduo" 10 | ) 11 | 12 | type DiscardServer struct { 13 | listener net.Listener 14 | } 15 | 16 | func NewDiscardServer(listenAddr string) *DiscardServer { 17 | server := new(DiscardServer) 18 | server.listener = muduo.ListenTcpOrDie(listenAddr) 19 | return server 20 | } 21 | 22 | func discard(c net.Conn) { 23 | defer c.Close() 24 | data := make([]byte, 4096) 25 | var total int64 26 | for { 27 | n, err := c.Read(data) 28 | total += int64(n) 29 | if err != nil { 30 | log.Println("discard:", err.Error()) 31 | break 32 | } 33 | } 34 | log.Println("total", total) 35 | printConn(c, "discard", "DOWN") 36 | } 37 | 38 | func discardAdv(c net.Conn) { 39 | defer c.Close() 40 | total, err := io.Copy(ioutil.Discard, c) 41 | if err != nil { 42 | log.Println("discard:", err.Error()) 43 | } 44 | log.Println("total", total) 45 | printConn(c, "discard", "DOWN") 46 | } 47 | 48 | func (s *DiscardServer) Serve() { 49 | serveTcp(s.listener, discardAdv, "discard") 50 | } 51 | -------------------------------------------------------------------------------- /examples/simple/echo.go: -------------------------------------------------------------------------------- 1 | package simple 2 | 3 | import ( 4 | "io" 5 | "log" 6 | "net" 7 | 8 | "github.com/chenshuo/muduo-examples-in-go/muduo" 9 | ) 10 | 11 | type EchoServer struct { 12 | listener net.Listener 13 | } 14 | 15 | func NewEchoServer(listenAddr string) *EchoServer { 16 | server := new(EchoServer) 17 | server.listener = muduo.ListenTcpOrDie(listenAddr) 18 | return server 19 | } 20 | 21 | func echo(c net.Conn) { 22 | defer c.Close() 23 | total, err := io.Copy(c, c) 24 | if err != nil { 25 | log.Println("echo:", err.Error()) 26 | } 27 | log.Println("total", total) 28 | printConn(c, "echo", "DOWN") 29 | } 30 | 31 | func (s *EchoServer) Serve() { 32 | serveTcp(s.listener, echo, "echo") 33 | } 34 | -------------------------------------------------------------------------------- /examples/simple/simple_allinone/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/chenshuo/muduo-examples-in-go/examples/simple" 5 | ) 6 | 7 | func main() { 8 | ch := make(chan bool) 9 | 10 | // long connection 11 | 12 | chargenServer := simple.NewChargenServer(":2019") 13 | go chargenServer.Serve() 14 | 15 | discardServer := simple.NewDiscardServer(":2009") 16 | go discardServer.Serve() 17 | 18 | echoServer := simple.NewEchoServer(":2007") 19 | go echoServer.Serve() 20 | 21 | // short connection 22 | 23 | daytimeServer := simple.NewDaytimeServer(":2013") 24 | go daytimeServer.Serve() 25 | 26 | timeServer := simple.NewTimeServer(":2037") 27 | go timeServer.Serve() 28 | 29 | <-ch // wait forever 30 | } 31 | -------------------------------------------------------------------------------- /examples/simple/simple_chargen/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/chenshuo/muduo-examples-in-go/examples/simple" 5 | ) 6 | 7 | func main() { 8 | chargenServer := simple.NewChargenServer(":2019") 9 | chargenServer.ServeWithMeter() 10 | } 11 | -------------------------------------------------------------------------------- /examples/simple/simple_chargenclient/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "io/ioutil" 7 | "log" 8 | "net" 9 | "os" 10 | 11 | "github.com/chenshuo/muduo-examples-in-go/muduo" 12 | ) 13 | 14 | func main() { 15 | if len(os.Args) != 2 { 16 | fmt.Printf("Usage: %s host\n", os.Args[0]) 17 | return 18 | } 19 | host := os.Args[1] 20 | conn, err := net.Dial("tcp", net.JoinHostPort(host, "2019")) 21 | muduo.PanicOnError(err) 22 | defer conn.Close() 23 | 24 | total, err := io.Copy(ioutil.Discard, conn) 25 | if err != nil { 26 | log.Println("discardclient:", err.Error()) 27 | } 28 | log.Println("total", total) 29 | } 30 | -------------------------------------------------------------------------------- /examples/simple/simple_daytime/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/chenshuo/muduo-examples-in-go/examples/simple" 5 | ) 6 | 7 | func main() { 8 | daytimeServer := simple.NewDaytimeServer(":2013") 9 | daytimeServer.Serve() 10 | } 11 | -------------------------------------------------------------------------------- /examples/simple/simple_discard/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/chenshuo/muduo-examples-in-go/examples/simple" 5 | ) 6 | 7 | func main() { 8 | discardServer := simple.NewDiscardServer(":2009") 9 | discardServer.Serve() 10 | } 11 | -------------------------------------------------------------------------------- /examples/simple/simple_echo/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/chenshuo/muduo-examples-in-go/examples/simple" 5 | ) 6 | 7 | func main() { 8 | echoServer := simple.NewEchoServer(":2019") 9 | echoServer.Serve() 10 | } 11 | -------------------------------------------------------------------------------- /examples/simple/simple_time/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/chenshuo/muduo-examples-in-go/examples/simple" 5 | ) 6 | 7 | func main() { 8 | timeServer := simple.NewTimeServer(":2037") 9 | timeServer.Serve() 10 | } 11 | -------------------------------------------------------------------------------- /examples/simple/simple_timeclient/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "net" 7 | "os" 8 | "time" 9 | 10 | "github.com/chenshuo/muduo-examples-in-go/muduo" 11 | ) 12 | 13 | func main() { 14 | if len(os.Args) != 2 { 15 | fmt.Printf("Usage: %s host\n", os.Args[0]) 16 | return 17 | } 18 | host := os.Args[1] 19 | conn, err := net.Dial("tcp", net.JoinHostPort(host, "2037")) 20 | muduo.PanicOnError(err) 21 | defer conn.Close() 22 | 23 | var unixtime int32 24 | err = binary.Read(conn, binary.BigEndian, &unixtime) 25 | muduo.PanicOnError(err) 26 | 27 | println(time.Unix(int64(unixtime), 0).String()) 28 | } 29 | -------------------------------------------------------------------------------- /examples/simple/time.go: -------------------------------------------------------------------------------- 1 | package simple 2 | 3 | import ( 4 | "encoding/binary" 5 | "log" 6 | "net" 7 | "time" 8 | 9 | "github.com/chenshuo/muduo-examples-in-go/muduo" 10 | ) 11 | 12 | type TimeServer struct { 13 | listener net.Listener 14 | } 15 | 16 | func NewTimeServer(listenAddr string) *TimeServer { 17 | server := new(TimeServer) 18 | server.listener = muduo.ListenTcpOrDie(listenAddr) 19 | return server 20 | } 21 | 22 | func (s *TimeServer) Serve() { 23 | defer s.listener.Close() 24 | for { 25 | conn, err := s.listener.Accept() 26 | if err == nil { 27 | printConn(conn, "time", "UP") 28 | var now int32 = int32(time.Now().Unix()) 29 | binary.Write(conn, binary.BigEndian, &now) 30 | printConn(conn, "time", "DOWN") 31 | conn.Close() 32 | } else { 33 | log.Println("time:", err.Error()) 34 | // TODO: break if ! temporary 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /examples/socks4a/tcprelay/tcprelay.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io" 5 | "log" 6 | "net" 7 | ) 8 | 9 | func panicOnError(err error) { 10 | if err != nil { 11 | panic(err) 12 | } 13 | } 14 | 15 | func relay(serverconn net.Conn) { 16 | defer serverconn.Close() 17 | log.Printf("relay: listen on %v, new client from %v\n", 18 | serverconn.LocalAddr().String(), serverconn.RemoteAddr().String()) 19 | 20 | clientconn, err := net.Dial("tcp", "localhost:3000") 21 | panicOnError(err) 22 | defer clientconn.Close() 23 | log.Printf("relay: connected to %v, from %v\n", 24 | clientconn.RemoteAddr().String(), clientconn.LocalAddr().String()) 25 | 26 | done := make(chan bool) 27 | go func() { 28 | io.Copy(clientconn, serverconn) 29 | log.Printf("relay: done copying serverconn to clientconn\n") 30 | tcpconn := clientconn.(*net.TCPConn) 31 | tcpconn.CloseWrite() 32 | done <- true 33 | }() 34 | 35 | io.Copy(serverconn, clientconn) 36 | log.Printf("relay: done copying clientconn to serverconn\n") 37 | tcpconn := serverconn.(*net.TCPConn) 38 | tcpconn.CloseWrite() 39 | <-done 40 | } 41 | 42 | func main() { 43 | listener, err := net.Listen("tcp", ":2000") 44 | panicOnError(err) 45 | defer listener.Close() 46 | for { 47 | conn, err := listener.Accept() 48 | if err != nil { 49 | continue // https://golang.org/src/net/http/server.go#L2274 50 | } 51 | go relay(conn) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /muduo/common.go: -------------------------------------------------------------------------------- 1 | package muduo 2 | 3 | import ( 4 | "log" 5 | "net" 6 | "time" 7 | ) 8 | 9 | func Check(v bool, msg string) { 10 | if !v { 11 | panic(msg) 12 | } 13 | } 14 | 15 | func PanicOnError(err error) { 16 | if err != nil { 17 | panic(err) 18 | } 19 | } 20 | 21 | func ListenTcpOrDie(listenAddr string) net.Listener { 22 | listener, err := net.Listen("tcp", listenAddr) 23 | PanicOnError(err) 24 | return listener 25 | } 26 | 27 | type TcpServer interface { 28 | ServeConn(net.Conn) 29 | } 30 | 31 | func ServeTcp(l net.Listener, server TcpServer, name string) error { 32 | defer l.Close() 33 | var tempDelay time.Duration // how long to sleep on accept failure 34 | for { 35 | conn, err := l.Accept() 36 | if err != nil { 37 | if ne, ok := err.(net.Error); ok && ne.Temporary() { 38 | if tempDelay == 0 { 39 | tempDelay = 5 * time.Millisecond 40 | } else { 41 | tempDelay *= 2 42 | } 43 | if max := 1 * time.Second; tempDelay > max { 44 | tempDelay = max 45 | } 46 | log.Printf("%v: Accept error: %v; retrying in %v", name, err, tempDelay) 47 | time.Sleep(tempDelay) 48 | continue 49 | } 50 | return err 51 | } 52 | tempDelay = 0 53 | go server.ServeConn(conn) 54 | } 55 | } 56 | --------------------------------------------------------------------------------