I have a server that is heavily based on this tutorial. After I applied additional changes to it, it worked just fine. But now I try to add socket.io
to it and it's having some issues now. After testing the socket.io
code I added, it seems to affect the mechanism by which client-side code (endpoints) calls server-side code (database queries, processing). When the log of the endpoint call appears on the terminal, the call reaches the client side of the server, but it doesn't seem to call the server side.
This is the code for the socket server:
package helpers import ( "fmt" "net/http" socketio "github.com/googollee/go-socket.io" "github.com/googollee/go-socket.io/engineio" "github.com/googollee/go-socket.io/engineio/transport" "github.com/googollee/go-socket.io/engineio/transport/polling" "github.com/googollee/go-socket.io/engineio/transport/websocket" ) var alloworiginfunc = func(r *http.request) bool { return true } func startsocket() { server := socketio.newserver(&engineio.options{ transports: []transport.transport{ &polling.transport{ checkorigin: alloworiginfunc, }, &websocket.transport{ checkorigin: alloworiginfunc, }, }, }) server.onconnect("/", func(s socketio.conn) error { s.setcontext("") fmt.println("connected:", s.id()) return nil }) server.onevent("/", "notice", func(s socketio.conn, msg string) { fmt.println("notice:", msg) s.emit("reply", "have "+msg) }) server.onerror("/", func(s socketio.conn, e error) { fmt.println("socket error:", e) }) server.ondisconnect("/", func(s socketio.conn, reason string) { fmt.println("closed", reason) }) go server.serve() defer server.close() http.handle("/socket.io/", server) http.handle("/", http.fileserver(http.dir("./asset"))) fmt.println("socket server serving at localhost:8000...") fmt.print(http.listenandserve(":8000", nil)) }
// main.go server side
package main import ( "flag" "fmt" "log" "net" pb "github.com/<me>/<project_name>/api/proto/out" "github.com/<me>/<project_name>/cmd/server/handlers" "github.com/<me>/<project_name>/cmd/server/helpers" "google.golang.org/grpc" "google.golang.org/grpc/credentials" ) func init() { helpers.databaseconnection() } var ( tls = flag.bool("tls", true, "connection uses tls if true, else plain tcp") certfile = flag.string("cert_file", "", "the tls cert file") keyfile = flag.string("key_file", "", "the tls key file") port = flag.int("port", 50051, "the server port") ) func main() { flag.parse() // helpers.startsocket() lis, err := net.listen("tcp", fmt.sprintf("localhost:%d", *port)) if err != nil { log.fatalf("failed to listen: %v", err) } var opts []grpc.serveroption if *tls { if *certfile == "" { *certfile = "service.pem" } if *keyfile == "" { *keyfile = "service.key" } creds, err := credentials.newservertlsfromfile(*certfile, *keyfile) if err != nil { log.fatalf("failed to generate credentials: %v", err) } opts = []grpc.serveroption{grpc.creds(creds)} } mserv := grpc.newserver(opts...) fmt.println("grpc server running ...") pb.registersomethingserviceserver(mserv, &handlers.somethingserver{}) log.printf("server listening at %v", lis.addr()) if err := mserv.serve(lis); err != nil { log.fatalf("failed to serve : %v", err) } }
// main.go client
package main import ( "bytes" "encoding/json" "flag" "fmt" "log" "sort" "strings" "github.com/<me>/<project_name>/cmd/client/handlers" "github.com/gin-gonic/gin" "google.golang.org/grpc" "google.golang.org/grpc/credentials" ) var ( addr = flag.string("addr", "localhost:50051", "the address to connect to") ) func main() { flag.parse() creds, err := credentials.newclienttlsfromfile("service.pem", "") if err != nil { log.fatalf("could not process the credentials: %v", err) } conn, err := grpc.dial(*addr, grpc.withtransportcredentials(creds)) if err != nil { log.fatalf("did not connect: %v", err) } defer conn.close() var gingine = gin.default() startclient(conn, gingine) } func startclient(conn *grpc.clientconn, gingine *gin.engine) { handlers.somethingapihandler(conn, gingine) gingine.run(":5000") }
For the complete client and server code, you can check out the tutorial I linked above. If I don't call startsocket()
, everything works fine.
When calling the api's endpoint, I get this error, which is raised by the code calling the server-side code:
"rpc error: code = unavailable desc = connection error: desc = "transport: error while dialing: dial tcp [::1]:50051: connectex: no connection could be made because the target machine actively refused it.""
code show as below:
ginGine.POST("/account/login", func(ctx *gin.Context) { var account models.Account err := ctx.ShouldBind(&account) if err != nil { ctx.JSON(http.StatusBadRequest, gin.H{ "error1": err.Error(), }) return } res, err := srvClient.service.ValidateAccount(ctx, &pb.ValidateAccountRequest{ Account: &pb.Account{ Id: account.ID, FirstName: account.FirstName, LastName: account.LastName, UserName: account.UserName, Password: account.Password, }, }) if err != nil { ctx.JSON(http.StatusBadRequest, gin.H{ "error2": err.Error(), }) return } ctx.JSON(http.StatusOK, gin.H{ "status": res.Status, "access_token": res.AccessToken, }) })
error2 is the content returned by the api call
This line of code is blocking, the function StartSocket()
will never return:
fmt.Print(http.ListenAndServe(":8000", nil))
For testing, you can add a log after it and the log message will not be printed.
You need to run StartSocket()
in a separate non-blocking goroutine.
Notes For example, this line is log.Fatal(http.ListenAndServe(":8000", nil))
. Your code swallowed an error.
The above is the detailed content of Starting socket server interferes with gRPC/http client server communication Golang. For more information, please follow other related articles on the PHP Chinese website!