我有一个很大程度上基于此的服务器tutorial https://www.golinuxcloud.com/go-grpc-crud-api-postgresql-db/。在我对其应用了额外的更改后,它工作得很好。但现在我想添加socket.io
对此,它现在遇到了一些问题。测试代码后socket.io
我添加的,它似乎影响了客户端代码(端点)调用服务器端代码(数据库查询、处理)的机制。当端点调用的日志出现在终端上时,调用到达服务器的客户端,但它似乎并未调用服务器端。
这是套接字服务器的代码:
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 服务器端
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 客户端
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")
}
对于完整的客户端和服务器代码,您可以查看我上面链接的教程。如果我不打电话StartSocket()
,一切正常。
当调用 API 的端点时,我收到此错误,该错误是由调用服务器端代码的代码引发的:
“rpc 错误:代码 = 不可用 desc = 连接错误:desc =
“传输:拨号时出错:拨打 tcp [::1]:50051: connectex: 否
由于目标机器主动拒绝而无法建立连接
它。””
代码如下所示:
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 是 API 调用返回的内容