Skip to content

rssllyn/go-raknet

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

You are here mostly because you are intested in raknet, which is a game networking engine for game developers. It has many features that are commonly used in a game, both on server and client. This projects focus on creating a golang-binding of its reliable-udp feature.

In the online game world where real-time is truely important, udp makes latency between client and server more predictable, at the expense of more bandwidth usage. A reliable-udp framework gives you the advantage of tcp where message arrival and order are guaranteed, while keep you from doing the dirty and complex re-transmit work.

how to use it

The examples directory contains a echo server and echo client, check the code to see how to use go-raknet to build a server or client program.

$ cd examples
$ go run echo-server.go
2017-07-14T23:31:59.046+0800	INFO	go-raknet/listener.go:255	packet received	{"message identifier": 19}
2017-07-14T23:31:59.046+0800	DEBUG	go-raknet/listener.go:263	remote address	{"ip:port": "127.0.0.1:53098"}
2017-07-14T23:31:59.046+0800	DEBUG	go-raknet/listener.go:284	new incoming connection received	{"session ID": 0}
2017-07-14T23:32:26.338+0800	INFO	go-raknet/listener.go:255	packet received	{"message identifier": 134}
2017-07-14T23:32:26.338+0800	DEBUG	go-raknet/listener.go:290	packet received for session	{"session ID": 0}
2017-07-14T23:32:26.338+0800	DEBUG	examples/echo-server.go:71	data received from client	{"hex": "68656c6c6f", "string": "hello"}
$ cd examples
$ go run echo-client.go
2017-07-14T23:31:58.992+0800	DEBUG	go-raknet/listener.go:178	connecting to server	{"server address": "127.0.0.1:8711"}
2017-07-14T23:31:58.992+0800	DEBUG	go-raknet/listener.go:186	local address before connect	{"host": "", "port": 0}
2017-07-14T23:31:59.035+0800	DEBUG	go-raknet/listener.go:201	local address after connected	{"host": "", "port": 0}
2017-07-14T23:31:59.035+0800	DEBUG	examples/echo-client.go:47	connection accepted
hello
2017-07-14T23:32:26.330+0800	DEBUG	examples/echo-client.go:68	sending	{"data": "hello"}
2017-07-14T23:32:26.348+0800	INFO	go-raknet/listener.go:63	packet received	{"message identifier": 134}
2017-07-14T23:32:26.348+0800	DEBUG	go-raknet/listener.go:68	packet data	{"hex": "68656c6c6f"}
2017-07-14T23:32:26.348+0800	DEBUG	examples/echo-client.go:80	data received from client	{"hex": "68656c6c6f", "string": "hello"}

how the wrapper work

Because raknet is written in c++, in order to call it from golang, we can use swig to generate a wrapper api.

In golang world, you probably have known cgo, which helps you to call c code from golang. In a package with cgo, you typically have some files with the "C" package imported, and with some magical "cgo" directives in the comment. Then you can call c functions through the C package. The go build tool can compile the go code as well as any c/c++ code in the package, and link with libraries specified in the "cgo" directive.

As noted above, through "C" package, you can only call functions. You cannot, say create a instance of a c++ class. Or call a templated c++ function since there are no such feature directly in golang. So, in order to call c++ code, we have to wrap the code with some c functions.

In order to create a new instance of a c++ template class, you create a c function that create an instance for a specific template type. In order to call a c++ method/function with default parameters, you have to write a serial of c functions, each accept a fixed number of parameters and gave default value for others internally.

This works, but doing all the work manually is tedious. This is where swig come to rescue. To put it simple, swig is nothing more than generating those c wrapper functions for us, according to some c/c++ declarations. The declarations are written in a swig interface file (usually with a .i extension). You can also define some helper c/c++ code in the interface file, and of course swig would also generate wrapper c function for helper code. All wrapper c functions are generated when you run swig command against the interface file. And, because those c wrapper functions usually have terrible naming, it also generates go code that call them (through cgo), so you even don't have to know how to use cgo.

In our case here, the wrapper directory contains source code from raknet, with _FindFirst.* renamed to FindFirst.* so that go build tool will not ignore them. Then, we define the swig interface file wrapper.i. The wrapper_wrap.cxx and wrapper.go are c and go wrapper code generated by swig, previous one have cxx extension because it is actually a c++ source file, although we only have to know the c wrapper code here.

The swig generated file is simply for users to pick up easily. But here is the swig command I run:

$ cd wrapper
$ swig -c++ -go -cgo -intgosize 64 wrapper.i

Apparently this only works on a 64-bit platform, but you can generate wrapper code by adjusting the arguments.

There is one more thing I have to do manually. The go wrapper code generated does not link with any system libraries, I have to add the following comment in the cgo directives part.

#cgo LDFLAGS: -lstdc++ -lm

It tells the linker to link with the two specified library.

Upon running go build, the compilers first compiles the raknet Source code here, and the c/c++ wrapper code. Then compile the go wrapper code that calling c wraper functions, and link them the some libraries specified previously in cgo directive.

It takes time to build the code in wrapper package, you are better of installing the package so that the compiler don't have to build this package every time you build other package that imports it.

$ cd wrapper
$ go install 

simpler api

The api provided by swig generated go wrapper code are close to the RakNet api. And the go wrapper make many uses of variadic functions to provide access to c++ methods with default parameters, which makes it hard for the user to provide arguments.

As a golang network programmer, we are more comfortable with net package components, such as net.Listener and net.Conn. The root go-raknet package provides that, hiding the complexity of RakNet and provides a cleaner interface that those generated by swig.

About

swig based golang binding of the reliable-udp framework RakNet, which is implemented with c++

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published