Skip to content

Commit 2295e8c

Browse files
committed
feat: Implement the gnet client
1 parent 6a654c8 commit 2295e8c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+528
-43
lines changed

acceptor_unix.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1919
// SOFTWARE.
2020

21+
//go:build linux || freebsd || dragonfly || darwin
2122
// +build linux freebsd dragonfly darwin
2223

2324
package gnet
@@ -54,7 +55,7 @@ func (svr *server) acceptNewConnection(_ netpoll.IOEvent) error {
5455
}
5556

5657
el := svr.lb.next(netAddr)
57-
c := newTCPConn(nfd, el, sa, netAddr)
58+
c := newTCPConn(nfd, el, sa, svr.opts.Codec, el.ln.lnaddr, netAddr)
5859

5960
err = el.poller.UrgentTrigger(el.loopRegister, c)
6061
if err != nil {
@@ -87,7 +88,7 @@ func (el *eventloop) loopAccept(_ netpoll.IOEvent) error {
8788
logging.LogErr(err)
8889
}
8990

90-
c := newTCPConn(nfd, el, sa, netAddr)
91+
c := newTCPConn(nfd, el, sa, el.svr.opts.Codec, el.ln.lnaddr, netAddr)
9192
if err = el.poller.AddRead(c.pollAttachment); err != nil {
9293
return err
9394
}

client.go

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package gnet
2+
3+
import (
4+
"context"
5+
"net"
6+
"os"
7+
"sync"
8+
9+
"golang.org/x/sys/unix"
10+
11+
gerrors "github.com/panjf2000/gnet/errors"
12+
"github.com/panjf2000/gnet/internal/netpoll"
13+
"github.com/panjf2000/gnet/internal/socket"
14+
"github.com/panjf2000/gnet/logging"
15+
)
16+
17+
type Client struct {
18+
opts *Options
19+
el *eventloop
20+
logFlush func() error
21+
}
22+
23+
func NewClient(eventHandler EventHandler, opts ...Option) (cli *Client, err error) {
24+
options := loadOptions(opts...)
25+
cli = new(Client)
26+
var logger logging.Logger
27+
if options.LogPath != "" {
28+
if logger, cli.logFlush, err = logging.CreateLoggerAsLocalFile(options.LogPath, options.LogLevel); err != nil {
29+
return
30+
}
31+
} else {
32+
logger = logging.GetDefaultLogger()
33+
}
34+
if options.Logger == nil {
35+
options.Logger = logger
36+
}
37+
if options.Codec == nil {
38+
cli.opts.Codec = new(BuiltInFrameCodec)
39+
}
40+
cli.opts = options
41+
var p *netpoll.Poller
42+
if p, err = netpoll.OpenPoller(); err != nil {
43+
return
44+
}
45+
svr := new(server)
46+
svr.opts = options
47+
svr.eventHandler = eventHandler
48+
svr.ln = new(listener)
49+
50+
svr.cond = sync.NewCond(&sync.Mutex{})
51+
if options.Ticker {
52+
svr.tickerCtx, svr.cancelTicker = context.WithCancel(context.Background())
53+
}
54+
el := new(eventloop)
55+
el.ln = svr.ln
56+
el.svr = svr
57+
el.poller = p
58+
el.buffer = make([]byte, 16*1024)
59+
el.connections = make(map[int]*conn)
60+
el.eventHandler = eventHandler
61+
cli.el = el
62+
return
63+
}
64+
65+
// Start starts the client event-loop, handing IO events.
66+
func (cli *Client) Start() error {
67+
cli.el.eventHandler.OnInitComplete(Server{})
68+
go cli.el.activateSubReactor(cli.opts.LockOSThread)
69+
// Start the ticker.
70+
if cli.opts.Ticker {
71+
go cli.el.loopTicker(cli.el.svr.tickerCtx)
72+
}
73+
return nil
74+
}
75+
76+
// Stop stops the client event-loop.
77+
func (cli *Client) Stop() (err error) {
78+
err = cli.el.poller.UrgentTrigger(func(_ interface{}) error { return gerrors.ErrServerShutdown }, nil)
79+
cli.el.svr.waitForShutdown()
80+
cli.el.eventHandler.OnShutdown(Server{})
81+
// Stop the ticker.
82+
if cli.opts.Ticker {
83+
cli.el.svr.cancelTicker()
84+
}
85+
if cli.logFlush != nil{
86+
err = cli.logFlush()
87+
}
88+
logging.Cleanup()
89+
return
90+
}
91+
92+
// Dial is like net.Dial().
93+
func (cli *Client) Dial(network, address string) (gc Conn, err error) {
94+
var c net.Conn
95+
c, err = net.Dial(network, address)
96+
if err != nil {
97+
return nil, err
98+
}
99+
defer c.Close()
100+
101+
v, ok := c.(interface{ File() (*os.File, error) })
102+
if !ok {
103+
return nil, gerrors.ErrUnsupportedProtocol
104+
}
105+
106+
var file *os.File
107+
file, err = v.File()
108+
if err != nil {
109+
return nil, err
110+
}
111+
fd := int(file.Fd())
112+
113+
var sockAddr unix.Sockaddr
114+
switch c.(type) {
115+
case *net.UnixConn:
116+
if sockAddr, _, _, err = socket.GetUnixSockAddr(c.LocalAddr().Network(), c.LocalAddr().String()); err != nil {
117+
return
118+
}
119+
gc = newTCPConn(fd, cli.el, sockAddr, cli.opts.Codec, c.LocalAddr(), c.RemoteAddr())
120+
case *net.TCPConn:
121+
if sockAddr, _, _, _, err = socket.GetTCPSockAddr(c.LocalAddr().Network(), c.LocalAddr().String()); err != nil {
122+
return nil, err
123+
}
124+
gc = newTCPConn(fd, cli.el, sockAddr, cli.opts.Codec, c.LocalAddr(), c.RemoteAddr())
125+
case *net.UDPConn:
126+
if sockAddr, _, _, _, err = socket.GetUDPSockAddr(c.LocalAddr().Network(), c.LocalAddr().String()); err != nil {
127+
return
128+
}
129+
gc = newUDPConn(fd, cli.el, c.LocalAddr(), sockAddr)
130+
default:
131+
return nil, gerrors.ErrUnsupportedProtocol
132+
}
133+
err = cli.el.poller.UrgentTrigger(cli.el.loopRegister, gc)
134+
if err != nil {
135+
gc.Close()
136+
}
137+
return
138+
}

0 commit comments

Comments
 (0)