writing to net.Conn tcp socket

1,140 views
Skip to first unread message

Andy Hall

unread,
Sep 11, 2020, 3:54:38 PM9/11/20
to golang-nuts
if I have multiple clients connected to a tcp server and I wish to write back to specific connections I can record the net.Conn value and then use the Write method on it...but when using Println I get the following for two clients...

&{{0xc000094000}}
&{{0xc000094080}}

which when testing with a simple write doesn't work...

package main
import "net"
var c net.Conn = "&{{0xc000094000}}"
func writeConn(c net.Conn) {
c.Write([]byte(string("Hello\n")))
}
func main() {
writeConn(c)
}

...and results in the following...

cannot use "&{{0xc000094000}}" (type string) as type net.Conn in assignment

clearly using Println to output the net.Conn is not a viable var to use so how could I do this ? I intend to record each users net.Conn in a database which can then be queried as required.

any help would be most greatly appreciated.

Mhd Shulhan

unread,
Sep 12, 2020, 12:43:09 AM9/12/20
to Andy Hall, golang-nuts
Either I miss something or Go has different socket concept, but last time I learn this is not how the network socket works in general.

First, &{{0xc000094000}} is the address of a variable. You can't convert an address from string back to variable, because that would be security issue. Usually socket connection is signed integer, in C you can assign integer value to variable let other process write into it. But in Go, connection is an interface/structure.

If you want to record each users, you have two options:

1) Let the user send unique ID (for example their user ID or email or username) on first accept.

2) Get unique ID from connection IP address (beware that two or more connection may come from the same IP address).

You then must have a map that store unique ID as key and net.Conn as value. So, if you want to send some value to specific user, you query the map first and if exist then you can proceeds.

I hope that helps.

Andy Hall

unread,
Sep 12, 2020, 2:55:34 AM9/12/20
to golang-nuts
I think this is exactly what I need to do...thanks very much. I'm looking forward to implementing it.

Andy Hall

unread,
Sep 12, 2020, 8:35:49 AM9/12/20
to golang-nuts
So this works fine...

func handleConnection(c net.Conn) {
// get user details
username := createUser(c, "Please enter you username (new users will be created / existing users will be loaded): ")
// map username to connection
var m = make(map[string]net.Conn)
m[username] = c
n := len(m)
fmt.Println(strconv.Itoa(n))

But due to the concurrent nature of the function ( I can't have player 1 blocking player 2 ) the map only ever has details of your own connection...as seen from the output of len on the server...

$ go run game-server.go 6666
1
1

I guess I need to handle this outside of a goroutine...

Andy Hall

unread,
Sep 12, 2020, 8:46:18 AM9/12/20
to golang-nuts
OK so I just moved the declaration of the map to the package itself which makes it universal...all working as expected. Thanks.

Martin Schnabel

unread,
Sep 12, 2020, 12:04:19 PM9/12/20
to Andy Hall, golang-nuts

Hi Andy,

a global map is the way to go, however writing an reading the map from multiple go routines will fail (in your case different handle calls for connections) because the map data structure is not safe for concurrent use and must be coordinated. the way it is usually solved is by adding another sync.Mutex (mutually exclusive) variable to ensure only one go routine at a has access to the map.

https://godoc.org/sync#Mutex

just a heads up, have fun!

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/eff5d382-7bc5-4f2e-9752-a3c850318c0fn%40googlegroups.com.

Brian Candler

unread,
Sep 12, 2020, 1:12:30 PM9/12/20
to golang-nuts
On Saturday, 12 September 2020 17:04:19 UTC+1, mb0 wrote:

a global map is the way to go, however writing an reading the map from multiple go routines will fail (in your case different handle calls for connections) because the map data structure is not safe for concurrent use and must be coordinated. the way it is usually solved is by adding another sync.Mutex (mutually exclusive) variable to ensure only one go routine at a has access to the map.


Another very common pattern is to have a separate goroutine for each connection, and then the goroutines communicate using channels.

Andy Hall

unread,
Sep 12, 2020, 1:28:43 PM9/12/20
to Martin Schnabel, golang-nuts
Thanks Martin...I'll be sure to add a mutex lock and unlock either
side of the map call...probably shouldn't have chosen a networked
multi-player game as my first project but I sure am learning a lot !!
It's a very fun language too.

Andy Hall

unread,
Sep 12, 2020, 1:35:03 PM9/12/20
to Brian Candler, golang-nuts
thanks brian...I have looked at sync / channels but I think the
simplicity of mutex should work fine for me.
> --
> You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
> To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/qsMfKWZ8HgI/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/1cc5595e-d2ef-4dda-ab27-ce2052752393o%40googlegroups.com.

Stephan Lukits

unread,
Sep 12, 2020, 2:27:05 PM9/12/20
to golan...@googlegroups.com
On 9/12/20 8:27 PM, Andy Hall wrote:
> Thanks Martin...I'll be sure to add a mutex lock and unlock either
> side of the map call...probably shouldn't have chosen a networked
> multi-player game as my first project but I sure am learning a lot !!
> It's a very fun language too.

There is also *sync.Map* with a nice documentation.

Andy Hall

unread,
Sep 12, 2020, 2:36:18 PM9/12/20
to golang-nuts
So far this is working...

// create map
var m = make(map[string]net.Conn)
// populate map with user connection
m[username] = c
// get user connection from map
conn := m[username]
// write to user connection
conn.Write([]byte(string(username + " has entered the room\n# ")))

but to handle the map not returning a result ( so I don't attempt to
write to a non-existent connection ) I need to know the zero value of
type net.Conn

does anyone know what this is ?? if only net.Conn was an integer or
string this would be simple...

or is the only solution to use the comma, ok method when testing the map ?

Brian Candler

unread,
Sep 12, 2020, 3:02:31 PM9/12/20
to golang-nuts
On Saturday, 12 September 2020 19:36:18 UTC+1, Andy Hall wrote:
to handle the map not returning a result ( so I don't attempt to
write to a non-existent connection ) I need to know the zero value of
type net.Conn


net.Conn is an interface, and therefore its zero value is "nil".

Note though that you don't need to know the zero value of a type to determine whether it's in a map or not. Use the two-value assignment form (value, ok := ...) to test if the value exists.

Running through the whole of tour.golang.org is highly recommended.  Several times :-)

Andy Hall

unread,
Sep 12, 2020, 3:19:09 PM9/12/20
to golang-nuts
Yep I did this in the end and it works fine...

var user string
for rows_users.Next() {
        rows_users.Scan(&user)
        if conn, ok := m[user]; ok {
                conn.Write([]byte(string(username + " has entered the room\n# ")))
        }
}

I think I will back off the project and go back to the docs as you suggest rather than ploughing through every problem I come across...as fun as that can be.

Reply all
Reply to author
Forward
0 new messages