api - Golang - API Server 和 Socket 同时存在

标签 api sockets go server

我尝试制作套接字来与我的客户通信。

在对我的 API 发出一些请求后,将创建一个套接字。这意味着,客户端连接自己(仅通过请求),但随后他加入了聊天,因此创建了一个套接字并将其链接到良好的 channel 。

我已经使用过套接字,所以我了解它是如何工作的(C、C++、C#、Java),但是我想做的,根据我在网上看到的,我认为这是可能的,但我不明白如何用 golang 处理它。

我创建第一个服务器:

func main() {
    r := mux.NewRouter()
    r.HandleFunc("/", HomeHandler)
    r.HandleFunc("/products", ProductsHandler)
    r.HandleFunc("/articles", ArticlesHandler)
    http.Handle("/", r)
}

但是对于套接字,我需要另一个吗?

package main

import "net"
import "fmt"
import "bufio"
import "strings" // only needed below for sample processing

func main() {

    fmt.Println("Launching server...")

    // listen on all interfaces
    ln, _ := net.Listen("tcp", ":8081")

    // accept connection on port
    conn, _ := ln.Accept()   

    // run loop forever (or until ctrl-c)
    for {     
        // will listen for message to process ending in newline (\n)
        message, _ := bufio.NewReader(conn).ReadString('\n')
        // output message received     
        fmt.Print("Message Received:", string(message))
        // sample process for string received     
        newmessage := strings.ToUpper(message)
        // send new string back to client     
        conn.Write([]byte(newmessage + "\n"))   
    } 
}

感谢帮助!

最佳答案

基于我们的聊天讨论。

OVER带有大量伪代码的简化示例

import (
    "net"
    "encoding/json"
    "errors"
)

type User struct {
    name string
}

type Message {
    Action string
    Params map[string]string
}

type Server struct {
    connected_users map[*User]net.Conn
    users_connected_with_each_other map[*User][]*User
    good_users map[string]*User
}

func (srv *Server) ListenAndServe(addr string) error {
    ln, err := net.Listen("tcp", addr)
    if err != nil {
        return err
    }
    return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})
}

func (srv *Server) Serve(l net.Listener) error {
    defer l.Close()

    for {
        rw, e := l.Accept()
        if e != nil {
            return e
        }

        // you want to create server_conn here with buffers, channels and stuff
        // to use async thread safe read/write from it
        go srv.serve_conn(rw)
    }
}

func (srv *Server) serve_conn(rw net.Conn) error {  
    dec := json.NewDecoder(rw)

    var message Message

    //read 1st message he sent, should be token to connect
    dec.Decode(&message)

    token := get_token(Message)

    user, ok := srv.good_users[token]

    if !ok {
        return errors.New("BAD USER!")
    }
    // store connected user
    srv.connected_users[user] = rw

    for {
        // async reader will be nice
        dec.Decode(&message)

        switch message.Action {
            case "Message":
                // find users to send message to
                if chats_with, err := users_connected_with_each_other[user]; err == nil {                   
                    for user_to_send_message_to := range chats_with {
                        // find connections to send message to
                        if conn, err := srv.connected_users[user_to_send_message_to]; err == nil {
                            // send json encoded message
                            err := json.NewEncoder(conn).Encode(message)
                            //if write failed store message for later
                        }
                    }
                }

            //other cases

            default:
                // log?
        }       
    }
}

func main() {
    known_users_with_tokens := make(map[string]*User)


    srv := &Server{
        connected_users: make(map[*User]net.Conn),
        users_connected_with_each_other: make(map[*User][]*User),
        good_users: known_users_with_tokens, // map is reference type, so treat it like pointer
    }
    // start our server
    go srv.ListenAndServe(":54321")


    ConnRequestHandler := function(w http.ResponseWriter, r *http.Request) {
        user := create_user_based_on_request(r)
        token := create_token(user)

        // now user will be able to connect to server with token
        known_users_with_tokens[token] = user
    }

    ConnectUsersHandler := function(user1,user2) {
        // you should guard your srv.* members to avoid concurrent read/writes to map
        srv.users_connected_with_each_other[user1] = append(srv.users_connected_with_each_other[user1], user2)
        srv.users_connected_with_each_other[user2] = append(srv.users_connected_with_each_other[user2], user1)
    }

    //initialize your API http.Server
    r := mux.NewRouter()
    r.HandleFunc("/", HomeHandler)
    r.HandleFunc("/products", ProductsHandler)
    r.HandleFunc("/articles", ArticlesHandler)
    r.HandleFunc("/connection_request", ConnRequestHandler) // added
    http.Handle("/", r)
}

调用 ConnectUsersHandler(user1, user2) 让他们相互通信。

known_users_with_tokens[token] = user 允许用户连接到服务器

您需要为与您的服务器的连接实现异步读取器/写入器。保持良好用户的有用结构。 保护服务器结构成员并提供线程安全访问以更新它。

UDP

看起来像 json.NewEncoder(connection).Encode(&message)json.NewDecoder(connection).Decode(&message) 是异步和线程安全的。所以你可以同时从不同的 goroutines 编写。无需手动同步,耶!

关于api - Golang - API Server 和 Socket 同时存在,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37408252/

相关文章:

Python:显示为列表 httplib.HTTPMessage 时出现问题

.net - JWT token : logout JWT token

go - 使用 'go run' 将 CLI 参数传递给可执行文件

go - 我可以在一个 go 模块中包含多个包吗?如何?

php - PayPal API 定期付款 - 每 15 个月付款一次

ios - 在 App iOS 7 中使用用户墙纸作为背景

javascript - Flash 作为 JavaScript 的套接字网关

java - java读取结果

sockets - 使用具有 "select"功能的非阻塞套接字有什么好处?

http - 解密后的反向代理服务文件