I need to connect to an existing websocket server using go lang - go

Theres a websocket running in my localhost on ws://localhost:8080/ws
I need go lang code that can create a websocket client and connect to this server.
My Google-Fu skills failed to teach me a simple way to do this.
Thank you.

Nevermind I found some helping code online. Now my code looks like this in case someone else needs this:
package main
import (
"net/http"
"text/template"
"code.google.com/p/go.net/websocket"
"fmt"
"os"
"time"
)
const address string = "localhost:9999"
func main() {
initWebsocketClient()
}
func initWebsocketClient() {
fmt.Println("Starting Client")
ws, err := websocket.Dial(fmt.Sprintf("ws://%s/ws", address), "", fmt.Sprintf("http://%s/", address))
if err != nil {
fmt.Printf("Dial failed: %s\n", err.Error())
os.Exit(1)
}
incomingMessages := make(chan string)
go readClientMessages(ws, incomingMessages)
i := 0
for {
select {
case <-time.After(time.Duration(2e9)):
i++
response := new(Message)
response.RequestID = i
response.Command = "Eject the hot dog."
err = websocket.JSON.Send(ws, response)
if err != nil {
fmt.Printf("Send failed: %s\n", err.Error())
os.Exit(1)
}
case message := <-incomingMessages:
fmt.Println(`Message Received:`,message)
}
}
}
func readClientMessages(ws *websocket.Conn, incomingMessages chan string) {
for {
var message string
// err := websocket.JSON.Receive(ws, &message)
err := websocket.Message.Receive(ws, &message)
if err != nil {
fmt.Printf("Error::: %s\n", err.Error())
return
}
incomingMessages <- message
}
}
Also as recoba suggested in the comment, there has been a new gorilla example here for the ones looking for a better solution.

Check out this event-based client, super easy: https://github.com/rgamba/evtwebsocket
Example:
package main
import (
"fmt"
"github.com/rgamba/evtwebsocket"
"golang.org/x/net/websocket"
)
func main() {
c := evtwebsocket.Conn{
OnConnected: func(w *websocket.Conn) {
fmt.Println("Connected")
},
OnMessage: func(msg []byte) {
fmt.Printf("Received message: %s\n", msg)
},
OnError: func(err error) {
fmt.Printf("** ERROR **\n%s\n", err.Error())
},
}
// Connect
c.Dial("ws://echo.websocket.org")
c.Send([]byte("TEST"), nil)
}

Related

Gorilla websocket is not closing

I want to open websocket server whenever i want to and close but server does not close after writing "exit" when i go back to my main() and i try to start again it fails saying "httpHandleFunc multiple registration '/' " how do i close websocket server permanently and go back to main and start server again like switch on/off.
Another issue i am facing is client side errors with Bad Handshake when using gorilla mux as a handler.
#Server-Side Code
https://go.dev/play/p/n_I4xzOomWz
package main
import (
"bufio"
"flag"
"fmt"
"net/http"
"os"
"strings"
"time"
"github.com/gorilla/mux"
"github.com/gorilla/websocket"
log "github.com/sirupsen/logrus"
)
const (
// Time allowed to write a message to the peer.
writeWait = 10 * time.Second
// Maximum message size allowed from peer.
maxMessageSize = 8192
// Time allowed to read the next pong message from the peer.
pongWait = 60 * time.Second
// Send pings to peer with this period. Must be less than pongWait.
pingPeriod = (pongWait * 9) / 10
// Time to wait before force close on connection.
closeGracePeriod = 2 * time.Second
)
var (
server http.Server
addr = "0.0.0.0:443"
upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
},
}
)
func ping(ws *websocket.Conn, done chan struct{}) {
ticker := time.NewTicker(pingPeriod)
defer ticker.Stop()
for {
select {
case <-ticker.C:
if err := ws.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(writeWait)); err != nil {
log.Println("ping:", err)
}
case <-done:
return
}
}
}
// write message
func pumpStdout(ws *websocket.Conn, done chan struct{}) {
defer func() {
}()
for {
text := ReadInput("User220 > ")
if text == "exit" {
break
}
ws.SetWriteDeadline(time.Now().Add(writeWait))
if err := ws.WriteMessage(websocket.TextMessage, []byte(text)); err != nil {
ws.Close()
log.Errorln(err)
break
}
}
close(done)
ws.SetWriteDeadline(time.Now().Add(writeWait))
ws.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
time.Sleep(closeGracePeriod)
ws.Close()
}
// receive message
func pumpStdin(ws *websocket.Conn, done chan struct{}) {
defer ws.Close()
ws.SetReadLimit(maxMessageSize)
ws.SetReadDeadline(time.Now().Add(pongWait))
ws.SetPongHandler(func(string) error { ws.SetReadDeadline(time.Now().Add(pongWait)); return nil })
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-done:
break
case <-ticker.C:
_, message, err := ws.ReadMessage()
if err != nil {
ws.CloseHandler()
err := ws.UnderlyingConn().Close()
fmt.Println(err)
main()
}
if len(message) > 0 {
fmt.Printf("\r\n%sUser220 > ", message)
}
}
}
}
func WebsocketHandle(w http.ResponseWriter, r *http.Request) {
c, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Fatalln(err)
}
defer c.Close()
stdoutDone := make(chan struct{})
go pumpStdout(c, stdoutDone)
go ping(c, stdoutDone)
pumpStdin(c, stdoutDone)
}
func start_socket() {
flag.Parse()
log.Printf("listen at %s", addr)
// ----------------------
mux := mux.NewRouter()
mux.HandleFunc("/", WebsocketHandle)
//-----------------------
http.HandleFunc("/", WebsocketHandle)
server = http.Server{Addr: addr}
log.Fatalln(server.ListenAndServe())
}
func stop_server() {
err := server.Close()
if err != nil {
log.Fatalln(err)
}
}
func ReadInput(promt string) string {
fmt.Printf("\n%s", promt)
reader := bufio.NewReader(os.Stdin)
input, _ := reader.ReadString('\n')
return strings.TrimSpace(input)
}
func main() {
for {
read := ReadInput("Main : ")
switch read {
case "start":
start_socket()
case "stop":
stop_server()
default:
fmt.Println("Not Sure")
}
}
}
Client side i am just polling and writing back the same message right now.
#Client-Side Code
https://go.dev/play/p/y4nUkvMFYec
package main
import (
"fmt"
"net/url"
"github.com/gorilla/websocket"
log "github.com/sirupsen/logrus"
)
var addr = "localhost:443"
func main() {
dial := websocket.Dialer{}
u := url.URL{Scheme: "ws", Host: addr, Path: "/"}
log.Printf("connecting to %s", u.String())
c, _, err := dial.Dial(u.String(), nil)
if err != nil {
log.Fatalln(err)
}
defer c.Close()
for {
_, message, err := c.ReadMessage()
if err != nil {
log.Fatalln(err)
}
fmt.Println("Recevied : " + string(message))
err = c.WriteMessage(websocket.TextMessage, message)
if err != nil {
log.Fatalln(err)
}
}
}

Web server and listening nats at the same time

My code reads input from terminal and send those value to nats while it needs to have an http endpoint.
Separately it works but when I combine all of them it does not read from nats. If you could point me to a right direction I would appreciate.
package main
import (
"bufio"
"fmt"
nats "github.com/nats-io/nats.go"
"html/template"
"log"
"net/http"
"os"
)
func main() {
wd, err := os.Getwd()
if err != nil {
log.Fatal(err)
}
tmpl := template.Must(template.ParseFiles(wd + "/template/main.html"))
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
data := TodoPageData{
PageTitle: "Demo",
}
tmpl.Execute(w, data)
})
http.ListenAndServe(":8081", nil)
type message struct {
content string
}
var messages []message
nc, err := nats.Connect(
nats.DefaultURL,
)
if err != nil {
log.Fatal(err)
}
defer nc.Close()
// Subscribe
if _, err := nc.Subscribe("updates", func(m *nats.Msg) {
fmt.Printf("Received a message: %s\n", string(m.Data))
}); err != nil {
log.Fatal(err)
}
// io r/w
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
if err := nc.Publish("updates", []byte(scanner.Text())); err != nil {
log.Fatal(err)
}
messages = append(messages, message{scanner.Text()})
for _, message := range messages {
fmt.Println(message.content)
}
}
if scanner.Err() != nil {
// handle error.
}
}
http.ListenAndServe is a blocking call. Start it on a new goroutine:
go http.ListenAndServe(":8081", nil)

tcp reset connection by peer

I have a problem launching multiple go routines over 90000 to do http requests via POST to the same server, both the server and the client are locally, some of the requests are executed successfully and some of them giving me this response read: connection reset by peer
Please notice I am posting a small amount of data in the provided example
but actually I am sending a huge amount of data using protobuf.
This is the server https://play.golang.org/p/r1-rYNuAos
package main
import (
"net/http"
"log"
"encoding/json"
)
var port string
type problem struct{
}
func main() {
p := &problem{}
p.server(":9090")
}
func (self *problem)server(port string) {
s := &http.Server{
Addr: port,
Handler: self,
}
log.Println("Server started")
// Should be last line as it is a blocking.
log.Fatal(s.ListenAndServe())
}
func (self *problem) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
if err := json.NewEncoder(w).Encode(map[string]interface{}{"created": true}); err != nil {
log.Fatal(err.Error())
}
}
And this is the client https://play.golang.org/p/Xx5qQoqrYm
package main
import (
"net/http"
"bytes"
"io/ioutil"
"log"
"fmt"
)
type problem struct{
}
func main() {
p := &problem{}
p.client(":9090")
}
func (self *problem)client(port string) {
var k int
for k=0;k<90000;k++ {
go func(){
nativeRequest, err := http.NewRequest(
"POST",
"http://127.0.0.1" + port + "/",
bytes.NewBuffer([]byte(`testing`)),
)
nativeRequest.Close = true
if err != nil {
fmt.Println(err.Error())
}
client := &http.Transport{
}
nativeResponse, err := client.RoundTrip(nativeRequest)
if err != nil {
log.Println(err.Error())
}
if nativeResponse != nil {
defer nativeResponse.Body.Close()
if err != nil {
fmt.Println(err.Error())
}
body, err := ioutil.ReadAll(nativeResponse.Body)
if err != nil {
fmt.Println(err.Error())
}
fmt.Println(string(body))
}
}()
}
}

rpc.ServerCodec Still Serving?

I was performing some RPC tests, and stumbled across a problem I can't seem to solve. In my testing I create three separate RPC servers, all of which I try to close and shutdown. However upon performing my last test (TestRpcCodecServerClientComm), it seems my client connection is connecting to the first RPC server I started (I know this because I at some point attached IDs to the RPCHandlers), even though I attempted everything I could to make sure it was shutdown. Though the code is not there I have attempted to inspect every single error I could, but that did not bring about anything.
rpc.go
package rbot
import (
"io"
"net"
"net/rpc"
"net/rpc/jsonrpc"
)
func RpcCodecClientWithPort(port string) (rpc.ClientCodec, error) {
conn, err := net.Dial("tcp", "localhost:"+port)
if err != nil {
return nil, err
}
return jsonrpc.NewClientCodec(conn), nil
}
func RpcCodecServer(conn io.ReadWriteCloser) rpc.ServerCodec {
return jsonrpc.NewServerCodec(conn)
}
rpc_test.go
package rbot
import (
"errors"
"fmt"
"net"
"net/rpc"
"testing"
)
type RPCHandler struct {
RPCServer net.Listener
conn rpc.ServerCodec
done chan bool
TestPort string
stop bool
GotRPC bool
}
func (r *RPCHandler) SetupTest() {
r.stop = false
r.GotRPC = false
r.done = make(chan bool)
r.TestPort = "5556"
}
// TODO: Create separate function to handle erroring
func (r *RPCHandler) CreateRPCServer() error {
rpc.RegisterName("TestMaster", TestAPI{r})
var err error
r.RPCServer, err = net.Listen("tcp", ":"+r.TestPort)
if err != nil {
return err
}
go func() {
for {
conn, err := r.RPCServer.Accept()
if err != nil || r.stop {
r.done <- true
return
}
r.conn = RpcCodecServer(conn)
rpc.ServeCodec(r.conn)
}
}()
return nil
}
func (r *RPCHandler) CloseRPCServer() error {
r.stop = true
if r.conn != nil {
err := r.conn.Close()
if err != nil {
fmt.Println(err)
}
}
err := r.RPCServer.Close()
<-r.done
return err
}
type TestAPI struct {
t *RPCHandler
}
func (tapi TestAPI) Send(msg string, result *string) error {
if msg == "Got RPC?" {
tapi.t.GotRPC = true
return nil
}
return errors.New("Didn't receive right message")
}
// Check if we can create and close an RPC server successfully using the RPC server codec.
func TestRpcCodecServer(t *testing.T) {
r := RPCHandler{}
r.SetupTest()
err := r.CreateRPCServer()
if err != nil {
t.Fatalf("Could not create rpc server! %s:", err.Error())
}
err = r.CloseRPCServer()
if err != nil {
t.Fatalf("Could not close RPC server! %s:", err.Error())
}
}
// Check if we can create a client without erroring.
func TestRpcCodecClientWithPortt(t *testing.T) {
r := RPCHandler{}
r.SetupTest()
r.CreateRPCServer()
defer r.CloseRPCServer()
RPCClient, err := RpcCodecClientWithPort(r.TestPort)
defer RPCClient.Close()
if err != nil {
t.Fatalf("Could not create an RPC client! %s:", err.Error())
}
}
// Let's double check and make sure our server and client can speak to each other
func TestRpcCodecServerClientComm(t *testing.T) {
r := RPCHandler{}
r.SetupTest()
r.CreateRPCServer()
defer r.CloseRPCServer()
RPCCodec, _ := RpcCodecClientWithPort(r.TestPort)
RPCClient := rpc.NewClientWithCodec(RPCCodec)
defer RPCClient.Close()
var result string
err := RPCClient.Call("TestMaster.Send", "Got RPC?", &result)
if err != nil {
t.Fatalf("Error while trying to send RPC message: %s", err.Error())
}
if !r.GotRPC {
t.Fatalf("Could not send correct message over RPC")
}
}
Not sure if I'm just mishandling the connection or something of the like, any help would be much appreciated.
For the Record The RPC api does receive the correct string message
While not the source of your problems, your test configuration has a few race conditions which you should take care of before they cause problems. Always check for issues with the -race option. You should also let the OS allocate the port so you don't run into conflicts. See for example how httptest.Server works.
Your failure here is that you're not creating a new rpc.Server for each test, you're reusing the rpc.DefaultServer. The first call to CreateRPCServer registers a TestAPI under the name TestMaster. Each subsequent call uses the already registered instance.
If you create a new rpc.Server each time you setup the test and register a new TestAPI, the final test will pass.
srv := rpc.NewServer()
srv.RegisterName("TestMaster", testAPI)
...
// and then use srv to handle the new connection
srv.ServeCodec(RpcCodecServer(conn))

go routine - why websocket reports the connection as closed?

I'm trying to create a client and a server using Go but for some reason the server reports the connection as "closed". As the code is trivial I can't think of anything wrong with my code. Any help is appreciated.
package main
import (
log "github.com/golang/glog"
"net/http"
"golang.org/x/net/websocket"
"time"
"flag"
)
type server struct {
payload chan string
}
// srv pushes the messages received via ws into srv.payload
func (srv *server) serve(ws *websocket.Conn) {
go func() {
var msg string
if err := websocket.Message.Receive(ws, &msg); err != nil {
log.Exit(err)
}
srv.payload <- msg
}()
return
}
// This example demonstrates a trivial client/ server.
func main() {
flag.Parse()
srv := server{payload: make(chan string, 10)}
http.Handle("/echo", websocket.Handler(srv.serve))
go func() {
err := http.ListenAndServe(":12345", nil)
if err != nil {
log.Errorf("ListenAndServe: " + err.Error())
}
}()
// give the server some time to start listening
time.Sleep(3 *time.Second)
//dial and test the response.
ws, err := websocket.Dial("ws://localhost:12345/echo", "", "http://localhost/?x=45")
if err != nil {
log.Exit(err)
}
ms := "test"
if err := websocket.Message.Send(ws, ms); err != nil {
log.Exit(err)
}
msg := <-srv.payload
if msg != ms{
log.Errorf("msg %v is not %v", ms)
}
}
Error
t.go:21] read tcp 127.0.0.1:12345->127.0.0.1:43135:
Edit:
After some try and error I've found that if I remove the go routine from the serve method it works but it doesn't make sense to me. Any idea why it doesn't work when websocket.Message.Receive is in a separate go routine?
package main
import (
log "github.com/golang/glog"
"net/http"
"golang.org/x/net/websocket"
"time"
"flag"
)
type server struct {
payload chan string
}
// srv pushes the messages received via ws into srv.payload
func (srv *server) serve(ws *websocket.Conn) {
var msg string
if err := websocket.Message.Receive(ws, &msg); err != nil {
log.Exit(err)
}
srv.payload <- msg
return
}
// This example demonstrates a trivial client/ server.
func main() {
flag.Parse()
srv := server{payload: make(chan string, 10)}
go func() {
http.Handle("/echo", websocket.Handler(srv.serve))
err := http.ListenAndServe(":12345", nil)
if err != nil {
log.Errorf("ListenAndServe: " + err.Error())
}
}()
// give the server some time to start listening
time.Sleep(3 *time.Second)
//dial and test the response.
ws, err := websocket.Dial("ws://localhost:12345/echo", "", "http://localhost/?x=45")
if err != nil {
log.Exit(err)
}
ms := "test"
if err := websocket.Message.Send(ws, ms); err != nil {
log.Exit(err)
}
msg := <-srv.payload
if msg != ms{
log.Errorf("msg %v is not %v", ms)
}
}
The websocket server closes the connection when the handler returns.
Removing the Go routine is the correct fix.

Resources