Home  >  Article  >  Backend Development  >  Where does the Golang jsonrpc2 server listen?

Where does the Golang jsonrpc2 server listen?

王林
王林forward
2024-02-08 21:27:28762browse

Golang jsonrpc2 服务器在哪里监听?

Where does the Golang jsonrpc2 server listen? This is a problem that many Golang developers often encounter when using the jsonrpc2 protocol. In Golang, where the jsonrpc2 server listens depends on how the code is implemented. A common practice is to have the server listen on a specific port in order to receive requests from clients. In addition, the server can also be monitored on a specific network interface, such as the local loopback interface (localhost) or a specified IP address. In order to ensure that the server can listen to requests and process them normally, developers need to clearly specify the listening location in the code.

Question content

I want to create a simple lsp server in golang, this is the code I have written so far:

package main

import (
    "context"
    "fmt"
    "os"
    "sync"

    "github.com/sourcegraph/jsonrpc2"
)

type lspserver struct {
    // the symmetric connection
    conn jsonrpc2.conn

    // check if the connection is available
    connmutex sync.mutex

    // shutdown
    shutdown bool
}

func newlspserver() *lspserver {
    return &lspserver{}
}

func (s *lspserver) initialize(ctx context.context) error {
    // to implement
    return nil
}

func (s *lspserver) handle(context.context, *jsonrpc2.conn, *jsonrpc2.request) (result interface{}, err error) {
    fmt.println("handling request...")
    // to implement
    return nil, nil
}

func (s *lspserver) serve(ctx context.context) {
    fmt.println("starting lsp server...")
    // what port is this server listening on?
    // it is listening on port 4389

    // create a new jsonrpc2 stream server
    handler := jsonrpc2.handlerwitherror(s.handle)

    // create a new jsonrpc2 stream server
    <-jsonrpc2.newconn(
        context.background(),
        jsonrpc2.newbufferedstream(os.stdin, jsonrpc2.vscodeobjectcodec{}),
        handler).disconnectnotify()
}

func main() {

    // create a new lsp server
    server := newlspserver()
    server.serve(context.background())

}

It works, but I don't know which port it runs on, or how to call it via the client in general. Does anyone have any ideas?

I think it should be port 4389, but not that one

I'm using this script for testing:

import json
import requests

def rpc_call(url, method, args):
    headers = {'content-type': 'application/json'}
    payload = {
        "method": method,
        "params": [args],
        "jsonrpc": "2.0",
        "id": 1,
    }
    response = requests.post(url, data=json.dumps(payload), headers=headers).json()
    return response['result']

url = 'http://localhost:4389/'

emailArgs = {'To': '[email&#160;protected]','Subject': 'Hello', 'Content': 'Hi!!!'}
smsArgs = {'Number': '381641234567', 'Content': 'Sms!!!'}
print(rpc_call(url, 'email.SendEmail', emailArgs))
print(rpc_call(url, 'sms.SendSMS', smsArgs))

I think this is correct because I got this client from another stackoverflow question

Solution

I see:

handlerwitherror(s.handle)

    // create a new jsonrpc2 stream server
    <-jsonrpc2.newconn(
        context.background(),
        jsonrpc2.newbufferedstream(os.stdin, jsonrpc2.vscodeobjectcodec{}),
        handler).disconnectnotify()
}

This means that your code uses json-rpc via standard input and output (stdin/stdout), instead of over a network connection.
When you use os.stdin as an argument to jsonrpc2.newbufferedstream, you specify that input should come from the standard input of the process running the server. and the response will be sent to standard output.

Therefore, the server is not listening on any network port. It interacts with data sent directly to its standard input and output. This is typically used for inter-process communication, for example when you want one process to call a server process and receive a response.
For example, see "go: Two-way communication with another process?" or davidelorenzoli/stdin-stdout-ipc.

If you want the json-rpc server to listen on a network port, you need to use the net package. You will also need to modify the client script to send its requests to the correct network port instead of sending an http request to the url.

package main

import (
    "context"
    "net"
    "log"
    "sync"

    "github.com/sourcegraph/jsonrpc2"
)

type LSPServer struct {
    // The symmetric connection
    conn jsonrpc2.Conn

    // Check if the connection is available
    connMutex sync.Mutex

    // shutdown
    shutdown bool
}

func NewLSPServer() *LSPServer {
    return &LSPServer{}
}

func (s *LSPServer) Initialize(ctx context.Context) error {
    // Initialize here if needed
    return nil
}

func (s *LSPServer) Handle(context.Context, *jsonrpc2.Conn, *jsonrpc2.Request) (result interface{}, err error) {
    fmt.Println("Handling request...")
    // Handle something
    return nil, nil
}

func (s *LSPServer) Serve(ctx context.Context) {
    fmt.Println("Starting LSP server...")
    
    // Listen on TCP port 4389 on all available unicast and
    // anycast IP addresses of the local system.
    l, err := net.Listen("tcp", "localhost:4389")
    if err != nil {
        log.Fatal(err)
    }
    defer l.Close()

    for {
        // Wait for a connection.
        conn, err := l.Accept()
        if err != nil {
            log.Fatal(err)
        }

        // Handle the connection in a new goroutine.
        go func(c net.Conn) {
            // Create a new jsonrpc2 stream server
            handler := jsonrpc2.HandlerWithError(s.Handle)
            <-jsonrpc2.NewConn(
                ctx,
                jsonrpc2.NewBufferedStream(c, jsonrpc2.VSCodeObjectCodec{}),
                handler).DisconnectNotify()
            c.Close()
        }(conn)
    }
}

func main() {
    // Create a new LSP server
    server := NewLSPServer()
    go server.Serve(context.Background()) // run Serve in a separate goroutine
    select {} // wait forever
}

This is a basic example where the serve method creates a tcp listener listening on port 4389 of localhost. It then enters a loop waiting for a connection, and when it gets a connection it starts a new goroutine to handle the connection using the json-rpc server.

On the client side, you need to open a tcp connection to the server, write the json-rpc request to that connection, and then read the response.

You cannot use the requests library like you would in a python script, because it is for http requests, not raw tcp connections.
You will need to use the socket library in python, or in your client's language, to create a tcp connection and send/receive data over it.

But remember, lsp (Language Server Protocol) runs over stdin/stdout and not a network socket.
This is because the lsp server is usually started as a child process by the editor/IDE and communicates directly through these channels. So depending on your use case, the raw stdin/stdout methods might be more appropriate.

The above is the detailed content of Where does the Golang jsonrpc2 server listen?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:stackoverflow.com. If there is any infringement, please contact admin@php.cn delete