I would like to see a minimal and simple example of how to connect to a websocket using gorilla.
The only example I found to connect to a websocket was this,
but I couldn't understand it, and I couldn't find an explanation of how it works.
Edit:
Line 20:
Why did he keep the websocket address in flag.String instead of a variable string?
Line 26:
Does this part create a signal that will notify the program when the user presses crtl + C?
interrupt: = make(chan os.Signal, 1)
signal.Notify (interrupt, os.Interrupt)
Line 32:
What does this line do?
websocket.DefaultDialer.Dial (u.String (), nil)
Line 60:
Because []byte(t.String()) instead of t.string()?
The sample's README says:
The client sends a message every second and prints all messages received.
Looking at the code, the latter part (prints all messages received) happens here:
go func() {
defer close(done)
for {
_, message, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
return
}
log.Printf("recv: %s", message)
}
}()
This spins up a goroutine that reads messages from c (the websocket connection) in a loop and prints them out. It stops when the read fails, which happens for errors and when the connection is closed.
The main goroutine does this:
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-done:
return
case t := <-ticker.C:
err := c.WriteMessage(websocket.TextMessage, []byte(t.String()))
if err != nil {
log.Println("write:", err)
return
}
case <-interrupt:
log.Println("interrupt")
// Cleanly close the connection by sending a close message and then
// waiting (with timeout) for the server to close the connection.
err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
if err != nil {
log.Println("write close:", err)
return
}
select {
case <-done:
case <-time.After(time.Second):
}
return
}
}
It has a ticker firing every second, on which a message is sent to the websocket. When the reader goroutine is done it closes the done channel, which signals this loop with the select to exit too.
Finally, there's an "interrupt" selection to handle Ctrl+C, cleanly stopping the client.
To answer your specific questions:
Line 20: this flag enables you to set the address from the command line when executing the program, instead of it being hardcoded. You can call it like client -addr localhost:9044 to set a different port, for example. See also https://gobyexample.com/command-line-flags
Line 26: yes this is for Ctrl+C; see also https://gobyexample.com/signals
Line 32: DefaultDialer is a preconfigured dialer in the websocket package. Per the documentation, it's equivalent to
var DefaultDialer = &Dialer{
Proxy: http.ProxyFromEnvironment,
HandshakeTimeout: 45 * time.Second,
}
Line 60: WriteMessage takes a []byte, so you have to convert the string to a []byte
Related
I'm trying to start an HTTP server in Go, and when the server is started, a message should be printed, in case of an error, an error message should be printed.
Given the following code:
const (
HTTPServerPort = ":4000"
)
func main() {
var httpServerError = make(chan error)
var waitGroup sync.WaitGroup
setupHTTPHandlers()
waitGroup.Add(1)
go func() {
defer waitGroup.Done()
httpServerError <- http.ListenAndServe(HTTPServerPort, nil)
}()
if <-httpServerError != nil {
fmt.Println("The Logging API service could not be started.", <-httpServerError)
} else {
fmt.Println("Logging API Service running # http://localhost" + HTTPServerPort)
}
waitGroup.Wait()
}
When I do start the application, I don't see anything printed to the console, where I would like to see:
Logging API Service running # http://localhost:4000
When I change the port to an invalid one, the following output is printed to the console:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
...app.go:45 +0x107
exit status 2
Could anyone point me in the right direction so that I know what I'm doing wrong with this implementation?
You can't do this unless you change the logic in your code or use Listen and Serve separately. Because ListenAndServe is a blocking function. If there something unexpected happens, it will return you an error. Provided it is not, it will keep blocking running the server. There is neither an event that is triggered whenever a server is started.
Let's run Listen and Serve separately then.
l, err := net.Listen("tcp", ":8080")
if err != nil {
// handle error
}
// Signal that server is open for business.
if err := http.Serve(l, rootHandler); err != nil {
// handle error
}
See https://stackoverflow.com/a/44598343/4792552.
P.S. net.Listen doesn't block because it runs in background. In other means, it simply spawns a socket connection in OS level and returns you with the details/ID of it. Thus, you use that ID to proxy orders to that socket.
The issue is that your if statement will always read from the httpServerError channel. However the only time something writes to that is if the server fails.
Try a select statement:
select{
case err := <-httpServerError
fmt.Println("The Logging API service could not be started.", err)
default:
fmt.Println("Logging API Service running # http://localhost" + HTTPServerPort
}
The default case will be ran if the channel does not have anything on it.
Notice this does not read from the channel twice like your example. Once you read a value from a channel, its gone. Think of it as a queue.
I have a test function which both creates a server and spawns a goroutine acting as a client. Now, simply sending a message from the client to the server works, but if I want to create an exchange, they seem to deadlock since the test never runs to completion (if no r/w deadlines are set). For example, I want the client to send a message to the server, the server to copy that message and send it back to the client, and then the client to verify that the received message was identical. Here is my test code:
func TestSendAwait(t *testing.T) {
m := "Hello World"
go func() {
conn, err := net.Dial("tcp", testingAddr)
if err != nil {
t.Fatal(err)
}
defer conn.Close()
t.Log("client connected to server") // DEBUG
conn.SetDeadline(time.Now().Add(2 * time.Second))
conn.Write([]byte(m))
conn.SetDeadline(time.Now().Add(2 * time.Second))
buf, err := ioutil.ReadAll(conn)
if err != nil {
t.Fatal(err)
}
t.Log(string(buf))
}()
ln, err := net.Listen("tcp", testingAddr)
if err != nil {
t.Fatal(err)
}
defer ln.Close()
t.Log("server started") // DEBUG
conn, err := ln.Accept()
if err != nil {
t.Fatal(err)
}
defer conn.Close()
t.Log("server received connection") // DEBUG
buf, err := ioutil.ReadAll(conn)
if err != nil {
t.Fatal(err)
}
t.Logf("server read buffer: %v", buf) // DEBUG
_, err = conn.Write(buf)
if err != nil {
t.Fatal(err)
}
t.Log("server wrote to connection") // DEBUG
}
The deadlines are set on the connection because otherwise the deadlock would be indefinite. The output is as follows:
transmission_test.go:42: server started
transmission_test.go:24: client connected to server
transmission_test.go:49: server received connection
transmission_test.go:32: read tcp 127.0.0.1:41164->127.0.0.1:9090: i/o timeout
transmission_test.go:55: server read buffer: [72 101 108 108 111 32 87 111 114 108 100]
transmission_test.go:61: server wrote to connection
Process finished with exit code 1
I don't understand why the client is unable to read and exits, and only then the server decides to send data down the socket? This happens even if I increase the read deadline in the client.
The program blocks on the call to ioutil.ReadAll. This function reads until io.EOF or some other error is returned.
One fix is to shutdown write after writing data to the connection. This will cause read on the peer to return io.EOF and for ioutil.ReadAll to return successfully.
conn.Write(data)
cw, ok := conn.(interface{ CloseWrite() error })
if !ok {
// handle error
}
cw.CloseWrite()
playground example
The program in the question does not guarantee that the listener is opened before the connection is dialed or that client will print print the received message. The playground example corrects these issues.
Another approach is to frame the messages in some way:
Write newline or some other byte sequence not allowed in message after message. Read until this byte sequence is found.
Write message length before message. Read length and then specified number of bytes.
I have a go program that uses a goroutine to read UDP packets.
I wanted to use a select clause and a "stopping" channel to close the goroutine to shut down as soon as it is not needed anymore.
Here is a simple code example for the goroutine:
func Run(c chan string, q chan bool, conn *net.UDPConn) {
defer close(c)
buf := make([]byte, 1024)
for {
select {
case <- q:
return
default:
n, _, err := conn.ReadFromUDP(buf)
c <- string(buf[0:n])
fmt.Println("Received ", string(buf[0:n]))
if err != nil {
fmt.Println("Error: ", err)
}
}
}
}
The connection is created as:
conn, err := net.ListenUDP("udp",addr.Addr)
And the goroutine is supposed to terminate using:
close(q)
After closing the "stopping" channel ("q") the goroutine does not immediately stop. I need to send one more string via the UDP connection. When doing so the goroutine stops.
I simply do not understand this behaviour and I would be grateful if somebody could enlighten me.
Thank you in advance!
Your program is likely stopped at this line when you close the channel:
n, _, err := conn.ReadFromUDP(buf)
Because execution is blocked at a ReadFrom method, the select statement is not being evaluated, therefore the close on channel q is not immediately detected. When you do another send on the UDP connection, ReadFrom unblocks and (once that loop iteration finishes) control moves to the select statement: at that point the close on q is detected.
You can close the connection to unblock ReadFrom, as was suggested in a comment. See the PacketConn documentation in the net package, especially "Any blocked ReadFrom or WriteTo operations will be unblocked and return errors":
// Close closes the connection.
// Any blocked ReadFrom or WriteTo operations will be unblocked and return errors.
Close() error
Depending on your needs a timeout might be an option as well, see again PacketConn documentation in the net package:
// ReadFrom reads a packet from the connection,
// copying the payload into b. It returns the number of
// bytes copied into b and the return address that
// was on the packet.
// ReadFrom can be made to time out and return
// an Error with Timeout() == true after a fixed time limit;
// see SetDeadline and SetReadDeadline.
ReadFrom(b []byte) (n int, addr Addr, err error)
So I've programmed a server that receives text messages from a connecting client, reverses and capses them and sends them back.
Now I'm trying to program a client so that when I launch it it will keep running until I shut it down (ctrl + c) and allow me to input text lines and send them to the server.
I have a problem though - if I pass a, say, cyrillic symbol to the input, it will return a <nil> <nil> (type, value) error and will remain bugged unless I flush the memory somehow.
I also can't figure how to read the whole message (whole meaning the size of the slice (1024 bytes)) instead of each word separately.
Also, how do I figure out how to delay my 'enter your message' text? Depending on the length of the message I pass on to the server, it should wait longer or shorter. I don't want it popping all over the place if the message is split into a few messages, just once after the answer is received.
Here's the relevant code:
func client() {
// connect to the server
c, err := net.Dial("tcp", "127.0.0.1"+":"+port)
if err != nil {
log.Printf("Dial error: %T %+v", err, err)
return
}
// send the message
msg := ""
for {
fmt.Print("Enter your message:\n")
_, errs := fmt.Scan(&msg)
if errs != nil {
log.Printf("Scan error: %T %+v", errs, errs)
return
}
fmt.Println("Client sending:\n", msg)
_, errw := c.Write([]byte(msg))
if errw != nil {
log.Printf("Write error: %T %+v", errw, errw)
return
}
// handle the response
go handleServerResponse(c)
time.Sleep(1 * time.Second)
}
func main() {
port = "9999"
// launch client
done := make(chan bool)
go client()
<-done // Block forever
}
I've used the empty channel to block the main() from ending.
How should I approach the 2 problems explained above?
Question answered by #JimB:
You're using fmt.Scan which scans space separated values. Don't use
that if you don't want to read each value separately. You can use
Scanln to read a line, or just read directly from stdin.
Snippet from WebSocket RFC:
To Start the WebSocket Closing Handshake with a status code (Section 7.4) /code/ and an optional close reason (Section 7.1.6) /reason/, an endpoint MUST send a Close control frame, as described in Section 5.5.1, whose status code is set to /code/ and whose close reason is set to /reason/. Once an endpoint has both sent and received a Close control frame, that endpoint SHOULD Close the WebSocket Connection as defined in Section 7.1.1.
I am trying to do the Close Handshake using Gorilla WebSocket package with the following code:
Server:
// Create upgrader function
conn, err := upgrader.Upgrade(w, r, nil)
// If there is an error stop everything.
if err != nil {
fmt.Println(err)
return
}
for {
// Read Messages
_, _, err := conn.ReadMessage()
// Client is programmed to send a close frame immediately...
// When reading close frame resend close frame with same
// reason and code
conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(1000, "woops"))
fmt.Println(err)
break
}
Client:
d := &websocket.Dialer{}
conn, _, err := d.Dial("ws://localhost:8080", nil)
if err != nil {
fmt.Println(err)
return
}
go func() {
for {
// Read Messages
_, _, err := conn.ReadMessage()
if c, k := err.(*websocket.CloseError); k {
if(c.Code == 1000) {
// Never entering since c.Code == 1005
fmt.Println(err)
break
}
}
}
}()
conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(1000, "woops"))
for {}
The server is reading the Close Frame as expected outputting the following:
websocket: close 1000 (normal): woops
However the client is like its stopping to read once it sends a close message. The ReadMessage continue to return error 1005. What am I doing wrong?
The server responds to a close frame with the code:
c.WriteControl(CloseMessage, []byte{}, time.Now().Add(writeWait))
This is translated to close code 1005 (no status received) by the client.
The 1000 oops close frame written by the server is not seen by the client application because the websocket connection stops reading from network after receiving the first close frame.
The client application should exit the loop when an error is returned from ReadMessage. There's no need to check for specific close codes.
for {
// Read Messages
_, _, err := conn.ReadMessage()
if err != nil {
break
}
}
Unrelated to the issue in the question, the server application should close the websocket connection after sending the close frame.
Also unrelated to the issue in the question, use select {} instead of for {} to block the main goroutine. The former simply blocks the goroutine. The latter spins using CPU time.